diff --git a/Content.Client/Actions/UI/ActionSlot.cs b/Content.Client/Actions/UI/ActionSlot.cs index b6fc2bb2c4..57ee669280 100644 --- a/Content.Client/Actions/UI/ActionSlot.cs +++ b/Content.Client/Actions/UI/ActionSlot.cs @@ -4,6 +4,7 @@ using Content.Client.Stylesheets; using Content.Shared.Actions; using Content.Shared.Actions.Components; using Content.Shared.Actions.Prototypes; +using Content.Shared.Inventory; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface; @@ -231,7 +232,7 @@ namespace Content.Client.Actions.UI { ActionPrototype actionPrototype => new ActionAttempt(actionPrototype), ItemActionPrototype itemActionPrototype => - (Item != null && IoCManager.Resolve().TryGetComponent(Item, out var itemActions)) ? + Item.HasValue && IoCManager.Resolve().TryGetComponent(Item, out var itemActions) ? new ItemActionAttempt(itemActionPrototype, Item.Value, itemActions) : null, _ => null }; diff --git a/Content.Client/Clothing/ClothingComponent.cs b/Content.Client/Clothing/ClothingComponent.cs index a75febecd8..1e6c9efcf7 100644 --- a/Content.Client/Clothing/ClothingComponent.cs +++ b/Content.Client/Clothing/ClothingComponent.cs @@ -1,14 +1,7 @@ -using Content.Client.Inventory; using Content.Client.Items.Components; -using Content.Shared.Clothing; -using Content.Shared.Inventory; using Content.Shared.Item; -using Robust.Client.Graphics; -using Robust.Client.ResourceManagement; -using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; -using Robust.Shared.IoC; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -20,85 +13,11 @@ namespace Content.Client.Clothing [NetworkedComponent()] public class ClothingComponent : ItemComponent { - [DataField("femaleMask")] - private FemaleClothingMask _femaleMask = FemaleClothingMask.UniformFull; public override string Name => "Clothing"; - private string? _clothingEquippedPrefix; - [ViewVariables(VVAccess.ReadWrite)] - [DataField("ClothingPrefix")] - public string? ClothingEquippedPrefix - { - get => _clothingEquippedPrefix; - set - { - if (_clothingEquippedPrefix == value) - return; - - _clothingEquippedPrefix = value; - - if(!Initialized) return; - - if (!Owner.TryGetContainer(out IContainer? container)) - return; - if (!IoCManager.Resolve().TryGetComponent(container.Owner, out ClientInventoryComponent? inventory)) - return; - if (!inventory.TryFindItemSlots(Owner, out EquipmentSlotDefines.Slots? slots)) - return; - - inventory.SetSlotVisuals(slots.Value, Owner); - } - } - - protected override void Initialize() - { - base.Initialize(); - ClothingEquippedPrefix = ClothingEquippedPrefix; - } - - [ViewVariables(VVAccess.ReadWrite)] - public FemaleClothingMask FemaleMask - { - get => _femaleMask; - set => _femaleMask = value; - } - - public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot, string? speciesId=null) - { - if (RsiPath == null) - return null; - - var rsi = IoCManager.Resolve().GetResource(SharedSpriteComponent.TextureRoot / RsiPath).RSI; - var prefix = ClothingEquippedPrefix ?? EquippedPrefix; - var stateId = prefix != null ? $"{prefix}-equipped-{slot}" : $"equipped-{slot}"; - if (speciesId != null) - { - var speciesState = $"{stateId}-{speciesId}"; - if (rsi.TryGetState(speciesState, out _)) - { - return (rsi, speciesState); - } - } - - if (rsi.TryGetState(stateId, out _)) - { - return (rsi, stateId); - } - - return null; - } - - public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) - { - if (curState is not ClothingComponentState state) - { - return; - } - - ClothingEquippedPrefix = state.ClothingEquippedPrefix; - EquippedPrefix = state.EquippedPrefix; - } + [DataField("femaleMask")] + public FemaleClothingMask FemaleMask { get; } = FemaleClothingMask.UniformFull; } public enum FemaleClothingMask : byte diff --git a/Content.Client/Clothing/ClothingSystem.cs b/Content.Client/Clothing/ClothingSystem.cs new file mode 100644 index 0000000000..decd235742 --- /dev/null +++ b/Content.Client/Clothing/ClothingSystem.cs @@ -0,0 +1,162 @@ +using System.Collections.Generic; +using Content.Client.Inventory; +using Content.Shared.CharacterAppearance; +using Content.Shared.Clothing; +using Content.Shared.Inventory; +using Content.Shared.Inventory.Events; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.ResourceManagement; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.IoC; + +namespace Content.Client.Clothing; + +public class ClothingSystem : EntitySystem +{ + /// + /// This is a shitty hotfix written by me (Paul) to save me from renaming all files. + /// For some context, im currently refactoring inventory. Part of that is slots not being indexed by a massive enum anymore, but by strings. + /// Problem here: Every rsi-state is using the old enum-names in their state. I already used the new inventoryslots ALOT. tldr: its this or another week of renaming files. + /// + private static readonly Dictionary TemporarySlotMap = new() + { + {"head", "HELMET"}, + {"eyes", "EYES"}, + {"ears", "EARS"}, + {"mask", "MASK"}, + {"outerClothing", "OUTERCLOTHING"}, + {"jumpsuit", "INNERCLOTHING"}, + {"neck", "NECK"}, + {"back", "BACKPACK"}, + {"belt", "BELT"}, + {"gloves", "HAND"}, + {"shoes", "FEET"}, + {"id", "IDCARD"}, + {"pocket1", "POCKET1"}, + {"pocket2", "POCKET2"}, + }; + + [Dependency] private IResourceCache _cache = default!; + [Dependency] private InventorySystem _inventorySystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnDidUnequip); + } + + private void OnDidUnequip(EntityUid uid, SpriteComponent component, DidUnequipEvent args) + { + component.LayerSetVisible(args.Slot, false); + } + + public void InitClothing(EntityUid uid, ClientInventoryComponent? component = null, SpriteComponent? sprite = null) + { + if (!_inventorySystem.TryGetSlots(uid, out var slots, component) || !Resolve(uid, ref sprite, ref component)) return; + + foreach (var slot in slots) + { + sprite.LayerMapReserveBlank(slot.Name); + + if (!_inventorySystem.TryGetSlotContainer(uid, slot.Name, out var containerSlot, out _, component) || + !containerSlot.ContainedEntity.HasValue) continue; + + RenderEquipment(uid, containerSlot.ContainedEntity.Value, slot.Name, component, sprite); + } + } + + private void OnGotEquipped(EntityUid uid, ClothingComponent component, GotEquippedEvent args) + { + if (!TryComp(args.Equipee, out var sprite) || !TryComp(args.Equipee, out var invComp)) + { + return; + } + + var data = GetEquippedStateInfo(args.Equipment, args.Slot, invComp.SpeciesId, component); + if (data != null) + { + var (rsi, state) = data.Value; + sprite.LayerSetVisible(args.Slot, true); + sprite.LayerSetState(args.Slot, state, rsi); + sprite.LayerSetAutoAnimated(args.Slot, true); + + if (args.Slot == "jumpsuit" && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) + { + sprite.LayerSetState(HumanoidVisualLayers.StencilMask, component.FemaleMask switch + { + FemaleClothingMask.NoMask => "female_none", + FemaleClothingMask.UniformTop => "female_top", + _ => "female_full", + }); + } + + return; + } + + + sprite.LayerSetVisible(args.Slot, false); + } + + private void RenderEquipment(EntityUid uid, EntityUid equipment, string slot, + ClientInventoryComponent? inventoryComponent = null, SpriteComponent? sprite = null, ClothingComponent? clothingComponent = null) + { + if(!Resolve(uid, ref inventoryComponent, ref sprite)) + return; + + if (!Resolve(equipment, ref clothingComponent, false)) + { + sprite.LayerSetVisible(slot, false); + return; + } + + var data = GetEquippedStateInfo(equipment, slot, inventoryComponent.SpeciesId, clothingComponent); + if (data == null) return; + var (rsi, state) = data.Value; + sprite.LayerSetVisible(slot, true); + sprite.LayerSetState(slot, state, rsi); + sprite.LayerSetAutoAnimated(slot, true); + + if (slot == "jumpsuit" && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) + { + sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothingComponent.FemaleMask switch + { + FemaleClothingMask.NoMask => "female_none", + FemaleClothingMask.UniformTop => "female_top", + _ => "female_full", + }); + } + } + + public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EntityUid uid, string slot, string? speciesId=null, ClothingComponent? component = null) + { + if (!Resolve(uid, ref component)) + return null; + + if (component.RsiPath == null) + return null; + + var rsi = _cache.GetResource(SharedSpriteComponent.TextureRoot / component.RsiPath).RSI; + var correctedSlot = slot; + TemporarySlotMap.TryGetValue(correctedSlot, out correctedSlot); + var stateId = component.EquippedPrefix != null ? $"{component.EquippedPrefix}-equipped-{correctedSlot}" : $"equipped-{correctedSlot}"; + if (speciesId != null) + { + var speciesState = $"{stateId}-{speciesId}"; + if (rsi.TryGetState(speciesState, out _)) + { + return (rsi, speciesState); + } + } + + if (rsi.TryGetState(stateId, out _)) + { + return (rsi, stateId); + } + + return null; + } +} diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 1327aa68e0..d0d31c32d0 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -57,7 +57,6 @@ namespace Content.Client.Entry "MagicMirror", "FloorTile", "ShuttleController", - "HumanInventoryController", "RandomInsulation", "Electrified", "Electrocution", diff --git a/Content.Client/Hands/HandButton.cs b/Content.Client/Hands/HandButton.cs index 8bd7c65d51..a2483a09f1 100644 --- a/Content.Client/Hands/HandButton.cs +++ b/Content.Client/Hands/HandButton.cs @@ -1,4 +1,5 @@ -using Content.Client.Items.UI; +using Content.Client.HUD; +using Content.Client.Items.UI; using Content.Shared.Hands.Components; using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; @@ -10,7 +11,7 @@ namespace Content.Client.Hands private bool _activeHand; private bool _highlighted; - public HandButton(Texture texture, Texture storageTexture, string textureName, Texture blockedTexture, HandLocation location) : base(texture, storageTexture, textureName) + public HandButton(int size, string textureName, string storageTextureName, IGameHud gameHud, Texture blockedTexture, HandLocation location) : base(size, textureName, storageTextureName, gameHud) { Location = location; diff --git a/Content.Client/Hands/HandsGui.xaml.cs b/Content.Client/Hands/HandsGui.xaml.cs index abe5f35685..e468c1bc7d 100644 --- a/Content.Client/Hands/HandsGui.xaml.cs +++ b/Content.Client/Hands/HandsGui.xaml.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Content.Client.HUD; +using Content.Client.Inventory; using Content.Client.Items.Managers; using Content.Client.Items.UI; using Content.Client.Resources; @@ -32,7 +33,7 @@ namespace Content.Client.Hands private readonly HandsSystem _handsSystem; private readonly HandsComponent _handsComponent; - private Texture StorageTexture => _gameHud.GetHudTexture("back.png"); + private string StorageTexture => "back.png"; private Texture BlockedTexture => _resourceCache.GetTexture("/Textures/Interface/Inventory/blocked.png"); private ItemStatusPanel StatusPanel { get; } @@ -166,9 +167,8 @@ namespace Content.Client.Hands HandLocation.Right => "hand_r.png", _ => "hand_l.png" }; - var buttonTexture = _gameHud.GetHudTexture(buttonTextureName); - return new HandButton(buttonTexture, StorageTexture, buttonTextureName, BlockedTexture, buttonLocation); + return new HandButton(ClientInventorySystem.ButtonSize, buttonTextureName, StorageTexture, _gameHud, BlockedTexture, buttonLocation); } private void UpdateHudTheme(int idx) diff --git a/Content.Client/Inventory/ClientInventoryComponent.cs b/Content.Client/Inventory/ClientInventoryComponent.cs index 0a52a5443f..0caac5e11e 100644 --- a/Content.Client/Inventory/ClientInventoryComponent.cs +++ b/Content.Client/Inventory/ClientInventoryComponent.cs @@ -1,17 +1,13 @@ using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Content.Client.Clothing; -using Content.Shared.CharacterAppearance; +using Content.Client.Items.UI; using Content.Shared.Inventory; -using Content.Shared.Movement.EntitySystems; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; -using static Content.Shared.Inventory.SharedInventoryComponent.ClientInventoryMessage; namespace Content.Client.Inventory { @@ -19,242 +15,21 @@ namespace Content.Client.Inventory /// A character UI which shows items the user has equipped within his inventory /// [RegisterComponent] - [ComponentReference(typeof(SharedInventoryComponent))] - public class ClientInventoryComponent : SharedInventoryComponent + [ComponentReference(typeof(InventoryComponent))] + [Friend(typeof(ClientInventorySystem))] + public class ClientInventoryComponent : InventoryComponent { - [Dependency] private readonly IEntityManager _entMan = default!; + public Control BottomLeftButtons = default!; + public Control BottomRightButtons = default!; + public Control TopQuickButtons = default!; - private readonly Dictionary _slots = new(); + public SS14Window InventoryWindow = default!; - public IReadOnlyDictionary AllSlots => _slots; - - [ViewVariables] public InventoryInterfaceController InterfaceController { get; private set; } = default!; - - [ComponentDependency] - private ISpriteComponent? _sprite; - - private bool _playerAttached = false; + public readonly Dictionary> SlotButtons = new(); [ViewVariables] [DataField("speciesId")] public string? SpeciesId { get; set; } - protected override void OnRemove() - { - base.OnRemove(); - - if (_playerAttached) - { - InterfaceController?.PlayerDetached(); - } - InterfaceController?.Dispose(); - } - - protected override void Initialize() - { - base.Initialize(); - - var controllerType = ReflectionManager.LooseGetType(InventoryInstance.InterfaceControllerTypeName); - var args = new object[] {this}; - InterfaceController = DynamicTypeFactory.CreateInstance(controllerType, args); - InterfaceController.Initialize(); - - if (_sprite != null) - { - foreach (var mask in InventoryInstance.SlotMasks.OrderBy(s => InventoryInstance.SlotDrawingOrder(s))) - { - if (mask == Slots.NONE) - { - continue; - } - - _sprite.LayerMapReserveBlank(mask); - } - } - - // Component state already came in but we couldn't set anything visually because, well, we didn't initialize yet. - foreach (var (slot, entity) in _slots) - { - _setSlot(slot, entity); - } - } - - public override bool IsEquipped(EntityUid item) - { - return item != default && _slots.Values.Any(e => e == item); - } - - public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) - { - base.HandleComponentState(curState, nextState); - - if (curState is not InventoryComponentState state) - return; - - var doneSlots = new HashSet(); - - foreach (var (slot, entity) in state.Entities) - { - if (!_entMan.EntityExists(entity)) - { - continue; - } - if (!_slots.ContainsKey(slot) || _slots[slot] != entity) - { - _slots[slot] = entity; - _setSlot(slot, entity); - } - doneSlots.Add(slot); - } - - if (state.HoverEntity != null) - { - var (slot, (entity, fits)) = state.HoverEntity.Value; - InterfaceController?.HoverInSlot(slot, entity, fits); - } - - foreach (var slot in _slots.Keys.ToList()) - { - if (!doneSlots.Contains(slot)) - { - _clearSlot(slot); - _slots.Remove(slot); - } - } - - EntitySystem.Get().RefreshMovementSpeedModifiers(Owner); - } - - private void _setSlot(Slots slot, EntityUid entity) - { - SetSlotVisuals(slot, entity); - - InterfaceController?.AddToSlot(slot, entity); - } - - internal void SetSlotVisuals(Slots slot, EntityUid entity) - { - if (_sprite == null) - { - return; - } - - if (_entMan.TryGetComponent(entity, out ClothingComponent? clothing)) - { - var flag = SlotMasks[slot]; - var data = clothing.GetEquippedStateInfo(flag, SpeciesId); - if (data != null) - { - var (rsi, state) = data.Value; - _sprite.LayerSetVisible(slot, true); - _sprite.LayerSetState(slot, state, rsi); - _sprite.LayerSetAutoAnimated(slot, true); - - if (slot == Slots.INNERCLOTHING && _sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) - { - _sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothing.FemaleMask switch - { - FemaleClothingMask.NoMask => "female_none", - FemaleClothingMask.UniformTop => "female_top", - _ => "female_full", - }); - } - - return; - } - } - - _sprite.LayerSetVisible(slot, false); - } - - internal void ClearAllSlotVisuals() - { - if (_sprite == null) - return; - - foreach (var slot in InventoryInstance.SlotMasks) - { - if (slot != Slots.NONE) - { - _sprite.LayerSetVisible(slot, false); - } - } - } - - private void _clearSlot(Slots slot) - { - InterfaceController?.RemoveFromSlot(slot); - _sprite?.LayerSetVisible(slot, false); - } - - public void SendEquipMessage(Slots slot) - { - var equipMessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip); -#pragma warning disable 618 - SendNetworkMessage(equipMessage); -#pragma warning restore 618 - } - - public void SendUseMessage(Slots slot) - { - var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Use); -#pragma warning disable 618 - SendNetworkMessage(equipmessage); -#pragma warning restore 618 - } - - public void SendHoverMessage(Slots slot) - { -#pragma warning disable 618 - SendNetworkMessage(new ClientInventoryMessage(slot, ClientInventoryUpdate.Hover)); -#pragma warning restore 618 - } - - public void SendOpenStorageUIMessage(Slots slot) - { -#pragma warning disable 618 - SendNetworkMessage(new OpenSlotStorageUIMessage(slot)); -#pragma warning restore 618 - } - - public void PlayerDetached() - { - InterfaceController.PlayerDetached(); - _playerAttached = false; - } - - public void PlayerAttached() - { - InterfaceController.PlayerAttached(); - _playerAttached = true; - } - - public override bool TryGetSlot(Slots slot, [NotNullWhen(true)] out EntityUid? item) - { - // dict TryGetValue uses default EntityUid, not null. - if (!_slots.ContainsKey(slot)) - { - item = null; - return false; - } - - item = _slots[slot]; - return item != null; - } - - public bool TryFindItemSlots(EntityUid item, [NotNullWhen(true)] out Slots? slots) - { - slots = null; - - foreach (var (slot, entity) in _slots) - { - if (entity == item) - { - slots = slot; - return true; - } - } - - return false; - } + public bool AttachedToGameHud; } } diff --git a/Content.Client/Inventory/ClientInventorySystem.cs b/Content.Client/Inventory/ClientInventorySystem.cs index b354ef2982..1b63e52612 100644 --- a/Content.Client/Inventory/ClientInventorySystem.cs +++ b/Content.Client/Inventory/ClientInventorySystem.cs @@ -1,20 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Content.Client.Clothing; using Content.Client.HUD; using Content.Shared.Input; +using Content.Client.Items.Managers; +using Content.Client.Items.UI; +using Content.Shared.CCVar; +using Content.Shared.Hands.Components; using Content.Shared.Inventory; -using Content.Shared.Movement.EntitySystems; -using Content.Shared.Slippery; +using Content.Shared.Inventory.Events; +using Content.Shared.Item; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.Configuration; using Robust.Shared.GameObjects; +using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; namespace Content.Client.Inventory { [UsedImplicitly] - public sealed class ClientInventorySystem : EntitySystem + public sealed class ClientInventorySystem : InventorySystem { [Dependency] private readonly IGameHud _gameHud = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly IItemSlotManager _itemSlotManager = default!; + [Dependency] private readonly ClothingSystem _clothingSystem = default!; + + public const int ButtonSize = 64; + private const int ButtonSeparation = 4; + private const int RightSeparation = 2; + + /// + /// Stores delegates used to create controls for a given . + /// + private readonly + Dictionary>, (SS14Window window, Control bottomLeft, Control bottomRight, Control + topQuick)>> + _uiGenerateDelegates = new(); public override void Initialize() { @@ -25,29 +57,96 @@ namespace Content.Client.Inventory InputCmdHandler.FromDelegate(_ => HandleOpenInventoryMenu())) .Register(); - SubscribeLocalEvent((_, component, _) => component.PlayerAttached()); - SubscribeLocalEvent((_, component, _) => component.PlayerDetached()); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); - SubscribeLocalEvent(OnSlipAttemptEvent); - SubscribeLocalEvent(OnRefreshMovespeed); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + + SubscribeLocalEvent(OnDidEquip); + SubscribeLocalEvent(OnDidUnequip); + + _config.OnValueChanged(CCVars.HudTheme, UpdateHudTheme); } - // jesus christ, this is duplicated to server/client, should really just be shared.. - private void OnSlipAttemptEvent(EntityUid uid, ClientInventoryComponent component, SlipAttemptEvent args) + public override bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false, + InventoryComponent? inventory = null, SharedItemComponent? item = null) { - if (component.TryGetSlot(EquipmentSlotDefines.Slots.SHOES, out EntityUid? shoes)) + if(!target.IsClientSide() && !actor.IsClientSide() && !itemUid.IsClientSide()) RaiseNetworkEvent(new TryEquipNetworkMessage(actor, target, itemUid, slot, silent, force)); + return base.TryEquip(actor, target, itemUid, slot, silent, force, inventory, item); + } + + public override bool TryUnequip(EntityUid actor, EntityUid target, string slot, [NotNullWhen(true)] out EntityUid? removedItem, bool silent = false, bool force = false, + InventoryComponent? inventory = null) + { + if(!target.IsClientSide() && !actor.IsClientSide()) RaiseNetworkEvent(new TryUnequipNetworkMessage(actor, target, slot, silent, force)); + return base.TryUnequip(actor, target, slot, out removedItem, silent, force, inventory); + } + + private void OnDidUnequip(EntityUid uid, ClientInventoryComponent component, DidUnequipEvent args) + { + if (component.SlotButtons.TryGetValue(args.Slot, out var buttons)) { - RaiseLocalEvent(shoes.Value, args, false); + foreach (var button in buttons) + { + _itemSlotManager.SetItemSlot(button, null); + } } } - private void OnRefreshMovespeed(EntityUid uid, ClientInventoryComponent component, RefreshMovementSpeedModifiersEvent args) + private void OnDidEquip(EntityUid uid, ClientInventoryComponent component, DidEquipEvent args) { - foreach (var (_, ent) in component.AllSlots) + if (component.SlotButtons.TryGetValue(args.Slot, out var buttons)) { - if (ent != default) + foreach (var button in buttons) { - RaiseLocalEvent(ent, args, false); + _itemSlotManager.SetItemSlot(button, args.Equipment); + } + } + } + + private void OnPlayerDetached(EntityUid uid, ClientInventoryComponent component, PlayerDetachedEvent? args = null) + { + if(!component.AttachedToGameHud) return; + + _gameHud.InventoryButtonVisible = false; + _gameHud.BottomLeftInventoryQuickButtonContainer.RemoveChild(component.BottomLeftButtons); + _gameHud.BottomRightInventoryQuickButtonContainer.RemoveChild(component.BottomRightButtons); + _gameHud.TopInventoryQuickButtonContainer.RemoveChild(component.TopQuickButtons); + component.AttachedToGameHud = false; + } + + private void OnShutdown(EntityUid uid, ClientInventoryComponent component, ComponentShutdown args) + { + OnPlayerDetached(uid, component); + } + + private void OnPlayerAttached(EntityUid uid, ClientInventoryComponent component, PlayerAttachedEvent args) + { + if(component.AttachedToGameHud) return; + + _gameHud.InventoryButtonVisible = true; + _gameHud.BottomLeftInventoryQuickButtonContainer.AddChild(component.BottomLeftButtons); + _gameHud.BottomRightInventoryQuickButtonContainer.AddChild(component.BottomRightButtons); + _gameHud.TopInventoryQuickButtonContainer.AddChild(component.TopQuickButtons); + component.AttachedToGameHud = true; + } + + private void UpdateHudTheme(int obj) + { + if (!_gameHud.ValidateHudTheme(obj)) + { + return; + } + + foreach (var inventoryComponent in EntityManager.EntityQuery(true)) + { + foreach (var slotButton in inventoryComponent.SlotButtons) + { + foreach (var btn in slotButton.Value) + { + btn.RefreshTextures(_gameHud); + } } } } @@ -55,9 +154,183 @@ namespace Content.Client.Inventory public override void Shutdown() { CommandBinds.Unregister(); + _config.UnsubValueChanged(CCVars.HudTheme, UpdateHudTheme); base.Shutdown(); } + private void OnInit(EntityUid uid, ClientInventoryComponent component, ComponentInit args) + { + _clothingSystem.InitClothing(uid, component); + + if (!TryGetUIElements(uid, out var window, out var bottomLeft, out var bottomRight, out var topQuick, + component)) + return; + + component.InventoryWindow = window; + component.BottomLeftButtons = bottomLeft; + component.BottomRightButtons = bottomRight; + component.TopQuickButtons = topQuick; + } + + private void HoverInSlotButton(EntityUid uid, string slot, ItemSlotButton button, InventoryComponent? inventoryComponent = null, SharedHandsComponent? hands = null) + { + if (!Resolve(uid, ref inventoryComponent)) + return; + + if (!Resolve(uid, ref hands, false)) + return; + + if (!hands.TryGetActiveHeldEntity(out var heldEntity)) + return; + + if(!TryGetSlotContainer(uid, slot, out var containerSlot, out var slotDef, inventoryComponent)) + return; + + _itemSlotManager.HoverInSlot(button, heldEntity, + CanEquip(uid, heldEntity, slot, out _, slotDef, inventoryComponent) && + containerSlot.CanInsert(heldEntity, EntityManager)); + } + + private void HandleSlotButtonPressed(EntityUid uid, string slot, ItemSlotButton button, + GUIBoundKeyEventArgs args) + { + if (TryGetSlotEntity(uid, slot, out var itemUid)) + { + if (!_itemSlotManager.OnButtonPressed(args, itemUid.Value) && args.Function == EngineKeyFunctions.UIClick) + { + RaiseNetworkEvent(new UseSlotNetworkMessage(uid, slot)); + } + return; + } + + if (args.Function != EngineKeyFunctions.UIClick) return; + TryEquipActiveHandTo(uid, slot); + } + + private bool TryGetUIElements(EntityUid uid, [NotNullWhen(true)] out SS14Window? invWindow, + [NotNullWhen(true)] out Control? invBottomLeft, [NotNullWhen(true)] out Control? invBottomRight, + [NotNullWhen(true)] out Control? invTopQuick, ClientInventoryComponent? component = null) + { + invWindow = null; + invBottomLeft = null; + invBottomRight = null; + invTopQuick = null; + + if (!Resolve(uid, ref component)) + return false; + + if(!_prototypeManager.TryIndex(component.TemplateId, out var template)) + return false; + + if (!_uiGenerateDelegates.TryGetValue(component.TemplateId, out var genfunc)) + { + _uiGenerateDelegates[component.TemplateId] = genfunc = (entityUid, list) => + { + var window = new SS14Window() + { + Title = Loc.GetString("human-inventory-window-title"), + Resizable = false + }; + window.OnClose += () => _gameHud.InventoryButtonDown = false; + var windowContents = new LayoutContainer + { + MinSize = (ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation, + ButtonSize * 4 + ButtonSeparation * 3) + }; + window.Contents.AddChild(windowContents); + + ItemSlotButton GetButton(SlotDefinition definition, string textureBack) + { + var btn = new ItemSlotButton(ButtonSize, $"{definition.TextureName}.png", textureBack, + _gameHud) + { + OnStoragePressed = (e) => + { + if (e.Function != EngineKeyFunctions.UIClick && + e.Function != ContentKeyFunctions.ActivateItemInWorld) + return; + RaiseNetworkEvent(new OpenSlotStorageNetworkMessage(entityUid, definition.Name)); + } + }; + btn.OnHover = (_) => + { + HoverInSlotButton(entityUid, definition.Name, btn); + }; + btn.OnPressed = (e) => + { + HandleSlotButtonPressed(entityUid, definition.Name, btn, e); + }; + return btn; + } + + void AddButton(SlotDefinition definition, Vector2i position) + { + var button = GetButton(definition, "back.png"); + LayoutContainer.SetPosition(button, position); + windowContents.AddChild(button); + if (!list.ContainsKey(definition.Name)) + list[definition.Name] = new(); + list[definition.Name].Add(button); + } + + void AddHUDButton(BoxContainer container, SlotDefinition definition) + { + var button = GetButton(definition, "back.png"); + container.AddChild(button); + if (!list.ContainsKey(definition.Name)) + list[definition.Name] = new(); + list[definition.Name].Add(button); + } + + var topQuick = new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Horizontal, + SeparationOverride = 5 + }; + var bottomRight = new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Horizontal, + SeparationOverride = 5 + }; + var bottomLeft = new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Horizontal, + SeparationOverride = 5 + }; + + const int sizep = (ButtonSize + ButtonSeparation); + + foreach (var slotDefinition in template.Slots) + { + switch (slotDefinition.UIContainer) + { + case SlotUIContainer.BottomLeft: + AddHUDButton(bottomLeft, slotDefinition); + break; + case SlotUIContainer.BottomRight: + AddHUDButton(bottomRight, slotDefinition); + break; + case SlotUIContainer.Top: + AddHUDButton(topQuick, slotDefinition); + break; + } + + AddButton(slotDefinition, slotDefinition.UIWindowPosition * sizep); + } + + return (window, bottomLeft, bottomRight, topQuick); + }; + } + + var res = genfunc(uid, component.SlotButtons); + invWindow = res.window; + invBottomLeft = res.bottomLeft; + invBottomRight = res.bottomRight; + invTopQuick = res.topQuick; + return true; + } + + private void HandleOpenInventoryMenu() { _gameHud.InventoryButtonDown = !_gameHud.InventoryButtonDown; diff --git a/Content.Client/Inventory/HumanInventoryInterfaceController.cs b/Content.Client/Inventory/HumanInventoryInterfaceController.cs deleted file mode 100644 index b63948460c..0000000000 --- a/Content.Client/Inventory/HumanInventoryInterfaceController.cs +++ /dev/null @@ -1,334 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Content.Client.HUD; -using Content.Client.Items.Managers; -using Content.Client.Items.UI; -using Content.Shared.CCVar; -using JetBrains.Annotations; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.Configuration; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using Robust.Shared.Maths; -using static Content.Shared.Inventory.EquipmentSlotDefines; -using static Robust.Client.UserInterface.Controls.BoxContainer; - -namespace Content.Client.Inventory -{ - // Dynamically instantiated by ClientInventoryComponent. - [UsedImplicitly] - public class HumanInventoryInterfaceController : InventoryInterfaceController - { - [Dependency] private readonly IGameHud _gameHud = default!; - [Dependency] private readonly IItemSlotManager _itemSlotManager = default!; - [Dependency] private readonly INetConfigurationManager _configManager = default!; - - private readonly Dictionary> _inventoryButtons - = new(); - - private ItemSlotButton _hudButtonPocket1 = default!; - private ItemSlotButton _hudButtonPocket2 = default!; - private ItemSlotButton _hudButtonShoes = default!; - private ItemSlotButton _hudButtonJumpsuit = default!; - private ItemSlotButton _hudButtonGloves = default!; - private ItemSlotButton _hudButtonNeck = default!; - private ItemSlotButton _hudButtonHead = default!; - private ItemSlotButton _hudButtonBelt = default!; - private ItemSlotButton _hudButtonBack = default!; - private ItemSlotButton _hudButtonOClothing = default!; - private ItemSlotButton _hudButtonId = default!; - private ItemSlotButton _hudButtonMask = default!; - private ItemSlotButton _hudButtonEyes = default!; - private ItemSlotButton _hudButtonEars = default!; - - private Control _topQuickButtonsContainer = default!; - private Control _bottomLeftQuickButtonsContainer = default!; - private Control _bottomRightQuickButtonsContainer = default!; - - public HumanInventoryInterfaceController(ClientInventoryComponent owner) : base(owner) - { - } - - public override void Initialize() - { - base.Initialize(); - _configManager.OnValueChanged(CCVars.HudTheme, UpdateHudTheme, invokeImmediately: true); - - _window = new HumanInventoryWindow(_gameHud); - _window.OnClose += () => GameHud.InventoryButtonDown = false; - foreach (var (slot, button) in _window.Buttons) - { - button.OnPressed = (e) => AddToInventory(e, slot); - button.OnStoragePressed = (e) => OpenStorage(e, slot); - button.OnHover = (_) => RequestItemHover(slot); - _inventoryButtons.Add(slot, new List {button}); - } - - void AddButton(out ItemSlotButton variable, Slots slot, string textureName) - { - var texture = _gameHud.GetHudTexture($"{textureName}.png"); - var storageTexture = _gameHud.GetHudTexture("back.png"); - variable = new ItemSlotButton(texture, storageTexture, textureName) - { - OnPressed = (e) => AddToInventory(e, slot), - OnStoragePressed = (e) => OpenStorage(e, slot), - OnHover = (_) => RequestItemHover(slot) - }; - _inventoryButtons[slot].Add(variable); - } - - AddButton(out _hudButtonPocket1, Slots.POCKET1, "pocket"); - AddButton(out _hudButtonPocket2, Slots.POCKET2, "pocket"); - AddButton(out _hudButtonId, Slots.IDCARD, "id"); - - AddButton(out _hudButtonBack, Slots.BACKPACK, "back"); - - AddButton(out _hudButtonBelt, Slots.BELT, "belt"); - - AddButton(out _hudButtonShoes, Slots.SHOES, "shoes"); - AddButton(out _hudButtonJumpsuit, Slots.INNERCLOTHING, "uniform"); - AddButton(out _hudButtonOClothing, Slots.OUTERCLOTHING, "suit"); - AddButton(out _hudButtonGloves, Slots.GLOVES, "gloves"); - AddButton(out _hudButtonNeck, Slots.NECK, "neck"); - AddButton(out _hudButtonMask, Slots.MASK, "mask"); - AddButton(out _hudButtonEyes, Slots.EYES, "glasses"); - AddButton(out _hudButtonEars, Slots.EARS, "ears"); - AddButton(out _hudButtonHead, Slots.HEAD, "head"); - - _topQuickButtonsContainer = new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - _hudButtonShoes, - _hudButtonJumpsuit, - _hudButtonOClothing, - _hudButtonGloves, - _hudButtonNeck, - _hudButtonMask, - _hudButtonEyes, - _hudButtonEars, - _hudButtonHead - }, - SeparationOverride = 5 - }; - - _bottomRightQuickButtonsContainer = new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - _hudButtonPocket1, - _hudButtonPocket2, - _hudButtonId, - }, - SeparationOverride = 5 - }; - _bottomLeftQuickButtonsContainer = new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - _hudButtonBelt, - _hudButtonBack - }, - SeparationOverride = 5 - }; - } - - public override SS14Window? Window => _window; - private HumanInventoryWindow? _window; - - public override IEnumerable GetItemSlotButtons(Slots slot) - { - if (!_inventoryButtons.TryGetValue(slot, out var buttons)) - { - return Enumerable.Empty(); - } - - return buttons; - } - - public override void AddToSlot(Slots slot, EntityUid entity) - { - base.AddToSlot(slot, entity); - - if (!_inventoryButtons.TryGetValue(slot, out var buttons)) - return; - - foreach (var button in buttons) - { - _itemSlotManager.SetItemSlot(button, entity); - button.OnPressed = (e) => HandleInventoryKeybind(e, slot); - } - } - - public override void RemoveFromSlot(Slots slot) - { - base.RemoveFromSlot(slot); - - if (!_inventoryButtons.TryGetValue(slot, out var buttons)) - { - return; - } - - foreach (var button in buttons) - { - ClearButton(button, slot); - } - } - - public override void HoverInSlot(Slots slot, EntityUid entity, bool fits) - { - base.HoverInSlot(slot, entity, fits); - - if (!_inventoryButtons.TryGetValue(slot, out var buttons)) - { - return; - } - - foreach (var button in buttons) - { - _itemSlotManager.HoverInSlot(button, entity, fits); - } - } - - protected override void HandleInventoryKeybind(GUIBoundKeyEventArgs args, Slots slot) - { - if (!_inventoryButtons.ContainsKey(slot)) - return; - if (!Owner.TryGetSlot(slot, out var item)) - return; - - if (!_itemSlotManager.OnButtonPressed(args, item.Value)) - base.HandleInventoryKeybind(args, slot); - } - - private void ClearButton(ItemSlotButton button, Slots slot) - { - button.OnPressed = (e) => AddToInventory(e, slot); - _itemSlotManager.SetItemSlot(button, default); - } - - public override void PlayerAttached() - { - base.PlayerAttached(); - - GameHud.BottomLeftInventoryQuickButtonContainer.AddChild(_bottomLeftQuickButtonsContainer); - GameHud.BottomRightInventoryQuickButtonContainer.AddChild(_bottomRightQuickButtonsContainer); - GameHud.TopInventoryQuickButtonContainer.AddChild(_topQuickButtonsContainer); - - // Update all the buttons to make sure they check out. - - foreach (var (slot, buttons) in _inventoryButtons) - { - foreach (var button in buttons) - { - ClearButton(button, slot); - } - - if (Owner.TryGetSlot(slot, out var entity)) - { - AddToSlot(slot, entity.Value); - } - } - } - - public override void PlayerDetached() - { - base.PlayerDetached(); - - GameHud.BottomRightInventoryQuickButtonContainer.RemoveChild(_bottomRightQuickButtonsContainer); - GameHud.BottomLeftInventoryQuickButtonContainer.RemoveChild(_bottomLeftQuickButtonsContainer); - GameHud.TopInventoryQuickButtonContainer.RemoveChild(_topQuickButtonsContainer); - - foreach (var (slot, list) in _inventoryButtons) - { - foreach (var button in list) - { - ClearButton(button, slot); - } - } - } - - public void UpdateHudTheme(int idx) - { - if (!_gameHud.ValidateHudTheme(idx)) - { - return; - } - - foreach (var (_, list) in _inventoryButtons) - { - foreach (var button in list) - { - button.Button.Texture = _gameHud.GetHudTexture($"{button.TextureName}.png"); - button.StorageButton.TextureNormal = _gameHud.GetHudTexture("back.png"); - } - } - } - - private class HumanInventoryWindow : SS14Window - { - private const int ButtonSize = 64; - private const int ButtonSeparation = 4; - private const int RightSeparation = 2; - - public IReadOnlyDictionary Buttons { get; } - - public HumanInventoryWindow(IGameHud gameHud) - { - Title = Loc.GetString("human-inventory-window-title"); - Resizable = false; - - var buttonDict = new Dictionary(); - Buttons = buttonDict; - - const int width = ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation; - const int height = ButtonSize * 4 + ButtonSeparation * 3; - - var windowContents = new LayoutContainer {MinSize = (width, height)}; - Contents.AddChild(windowContents); - - void AddButton(Slots slot, string textureName, Vector2 position) - { - var texture = gameHud.GetHudTexture($"{textureName}.png"); - var storageTexture = gameHud.GetHudTexture("back.png"); - var button = new ItemSlotButton(texture, storageTexture, textureName); - - LayoutContainer.SetPosition(button, position); - - windowContents.AddChild(button); - buttonDict.Add(slot, button); - } - - const int sizep = (ButtonSize + ButtonSeparation); - - // Left column. - AddButton(Slots.EYES, "glasses", (0, 0)); - AddButton(Slots.NECK, "neck", (0, sizep)); - AddButton(Slots.INNERCLOTHING, "uniform", (0, 2 * sizep)); - AddButton(Slots.POCKET1, "pocket", (0, 3 * sizep)); - - // Middle column. - AddButton(Slots.HEAD, "head", (sizep, 0)); - AddButton(Slots.MASK, "mask", (sizep, sizep)); - AddButton(Slots.OUTERCLOTHING, "suit", (sizep, 2 * sizep)); - AddButton(Slots.SHOES, "shoes", (sizep, 3 * sizep)); - - // Right column - AddButton(Slots.EARS, "ears", (2 * sizep, 0)); - AddButton(Slots.IDCARD, "id", (2 * sizep, sizep)); - AddButton(Slots.GLOVES, "gloves", (2 * sizep, 2 * sizep)); - AddButton(Slots.POCKET2, "pocket", (2 * sizep, 3 * sizep)); - - // Far right column. - AddButton(Slots.BACKPACK, "back", (3 * sizep, 0)); - AddButton(Slots.BELT, "belt", (3 * sizep, sizep)); - } - } - } -} diff --git a/Content.Client/Inventory/InventoryInterfaceController.cs b/Content.Client/Inventory/InventoryInterfaceController.cs deleted file mode 100644 index 16f3efdf8f..0000000000 --- a/Content.Client/Inventory/InventoryInterfaceController.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using Content.Client.HUD; -using Content.Client.Items.UI; -using Content.Shared.Input; -using Content.Shared.Inventory; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.GameObjects; -using Robust.Shared.Input; -using Robust.Shared.IoC; - -namespace Content.Client.Inventory -{ - public abstract class InventoryInterfaceController : IDisposable - { - [Dependency] protected readonly IGameHud GameHud = default!; - - protected InventoryInterfaceController(ClientInventoryComponent owner) - { - Owner = owner; - } - - public virtual void Initialize() - { - } - - public abstract SS14Window? Window { get; } - protected ClientInventoryComponent Owner { get; } - - public virtual void PlayerAttached() - { - GameHud.InventoryButtonVisible = true; - } - - public virtual void PlayerDetached() - { - GameHud.InventoryButtonVisible = false; - } - - public virtual void Dispose() - { - } - - /// the button controls associated with the - /// specified slot, if any. Empty if none. - public abstract IEnumerable GetItemSlotButtons(EquipmentSlotDefines.Slots slot); - - public virtual void AddToSlot(EquipmentSlotDefines.Slots slot, EntityUid entity) - { - } - - public virtual void HoverInSlot(EquipmentSlotDefines.Slots slot, EntityUid entity, bool fits) - { - } - - public virtual void RemoveFromSlot(EquipmentSlotDefines.Slots slot) - { - } - - protected virtual void HandleInventoryKeybind(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot) - { - if (args.Function == EngineKeyFunctions.UIClick) - { - UseItemOnInventory(slot); - } - } - - protected void AddToInventory(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot) - { - if (args.Function != EngineKeyFunctions.UIClick) - { - return; - } - - Owner.SendEquipMessage(slot); - } - - protected void UseItemOnInventory(EquipmentSlotDefines.Slots slot) - { - Owner.SendUseMessage(slot); - } - - protected void OpenStorage(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot) - { - if (args.Function != EngineKeyFunctions.UIClick && args.Function != ContentKeyFunctions.ActivateItemInWorld) - { - return; - } - - Owner.SendOpenStorageUIMessage(slot); - } - - protected void RequestItemHover(EquipmentSlotDefines.Slots slot) - { - Owner.SendHoverMessage(slot); - } - } -} diff --git a/Content.Client/Inventory/StrippableBoundUserInterface.cs b/Content.Client/Inventory/StrippableBoundUserInterface.cs index dee8e4f03c..b690abbc76 100644 --- a/Content.Client/Inventory/StrippableBoundUserInterface.cs +++ b/Content.Client/Inventory/StrippableBoundUserInterface.cs @@ -7,14 +7,13 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Client.Inventory { [UsedImplicitly] public class StrippableBoundUserInterface : BoundUserInterface { - public Dictionary? Inventory { get; private set; } + public Dictionary<(string ID, string Name), string>? Inventory { get; private set; } public Dictionary? Hands { get; private set; } public Dictionary? Handcuffs { get; private set; } @@ -55,9 +54,9 @@ namespace Content.Client.Inventory { foreach (var (slot, name) in Inventory) { - _strippingMenu.AddButton(SlotNames[slot], name, (ev) => + _strippingMenu.AddButton(slot.Name, name, (ev) => { - SendMessage(new StrippingInventoryButtonPressed(slot)); + SendMessage(new StrippingInventoryButtonPressed(slot.ID)); }); } } diff --git a/Content.Client/Items/Managers/IItemSlotManager.cs b/Content.Client/Items/Managers/IItemSlotManager.cs index c5533a841a..5cf555554b 100644 --- a/Content.Client/Items/Managers/IItemSlotManager.cs +++ b/Content.Client/Items/Managers/IItemSlotManager.cs @@ -9,10 +9,10 @@ namespace Content.Client.Items.Managers { bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid item); void UpdateCooldown(ItemSlotButton? cooldownTexture, EntityUid entity); - bool SetItemSlot(ItemSlotButton button, EntityUid entity); + bool SetItemSlot(ItemSlotButton button, EntityUid? entity); void HoverInSlot(ItemSlotButton button, EntityUid entity, bool fits); event Action? EntityHighlightedUpdated; - bool IsHighlighted(EntityUid uid); + bool IsHighlighted(EntityUid? uid); /// /// Highlight all slot controls that contain the specified entity. diff --git a/Content.Client/Items/Managers/ItemSlotManager.cs b/Content.Client/Items/Managers/ItemSlotManager.cs index 83d250e792..291ad88a24 100644 --- a/Content.Client/Items/Managers/ItemSlotManager.cs +++ b/Content.Client/Items/Managers/ItemSlotManager.cs @@ -28,9 +28,9 @@ namespace Content.Client.Items.Managers public event Action? EntityHighlightedUpdated; - public bool SetItemSlot(ItemSlotButton button, EntityUid entity) + public bool SetItemSlot(ItemSlotButton button, EntityUid? entity) { - if (entity == default) + if (entity == null) { button.SpriteView.Sprite = null; button.StorageButton.Visible = false; @@ -141,9 +141,10 @@ namespace Content.Client.Items.Managers button.HoverSpriteView.Sprite = hoverSprite; } - public bool IsHighlighted(EntityUid uid) + public bool IsHighlighted(EntityUid? uid) { - return _highlightEntities.Contains(uid); + if (uid == null) return false; + return _highlightEntities.Contains(uid.Value); } public void HighlightEntity(EntityUid uid) diff --git a/Content.Client/Items/UI/ItemSlotButton.cs b/Content.Client/Items/UI/ItemSlotButton.cs index 499dcc31bf..181d651b35 100644 --- a/Content.Client/Items/UI/ItemSlotButton.cs +++ b/Content.Client/Items/UI/ItemSlotButton.cs @@ -1,15 +1,18 @@ using System; using Content.Client.Cooldown; +using Content.Client.HUD; using Content.Client.Items.Managers; using Content.Client.Stylesheets; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; +using Robust.Client.Utility; using Robust.Shared.GameObjects; using Robust.Shared.Input; using Robust.Shared.IoC; using Robust.Shared.Maths; +using Robust.Shared.Utility; namespace Content.Client.Items.UI { @@ -19,7 +22,7 @@ namespace Content.Client.Items.UI [Dependency] private readonly IItemSlotManager _itemSlotManager = default!; - public EntityUid Entity { get; set; } + public EntityUid? Entity { get; set; } public TextureRect Button { get; } public SpriteView SpriteView { get; } public SpriteView HoverSpriteView { get; } @@ -35,19 +38,19 @@ namespace Content.Client.Items.UI private readonly PanelContainer _highlightRect; - public string TextureName { get; set; } + private string _textureName; + private string _storageTextureName; - public ItemSlotButton(Texture texture, Texture storageTexture, string textureName) + public ItemSlotButton(int size, string textureName, string storageTextureName, IGameHud gameHud) { + _textureName = textureName; + _storageTextureName = storageTextureName; IoCManager.InjectDependencies(this); - MinSize = (64, 64); - - TextureName = textureName; + MinSize = (size, size); AddChild(Button = new TextureRect { - Texture = texture, TextureScale = (2, 2), MouseFilter = MouseFilterMode.Stop }); @@ -75,7 +78,6 @@ namespace Content.Client.Items.UI AddChild(StorageButton = new TextureButton { - TextureNormal = storageTexture, Scale = (0.75f, 0.75f), HorizontalAlignment = HAlignment.Right, VerticalAlignment = VAlignment.Bottom, @@ -108,6 +110,14 @@ namespace Content.Client.Items.UI { Visible = false, }); + + RefreshTextures(gameHud); + } + + public void RefreshTextures(IGameHud gameHud) + { + Button.Texture = gameHud.GetHudTexture(_textureName); + StorageButton.TextureNormal = gameHud.GetHudTexture(_storageTextureName); } protected override void EnteredTree() diff --git a/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs b/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs index db70686e8b..167d594315 100644 --- a/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs +++ b/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs @@ -4,6 +4,7 @@ using Content.Client.Inventory; using Content.Client.Preferences; using Content.Shared.CharacterAppearance.Systems; using Content.Shared.GameTicking; +using Content.Shared.Inventory; using Content.Shared.Preferences; using Content.Shared.Roles; using Robust.Client.GameObjects; @@ -15,7 +16,6 @@ using Robust.Shared.Localization; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Prototypes; -using static Content.Shared.Inventory.EquipmentSlotDefines; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Lobby.UI @@ -141,29 +141,30 @@ namespace Content.Client.Lobby.UI public static void GiveDummyJobClothes(EntityUid dummy, HumanoidCharacterProfile profile) { var protoMan = IoCManager.Resolve(); - var entMan = IoCManager.Resolve(); - var inventory = entMan.GetComponent(dummy); + var invSystem = EntitySystem.Get(); var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key; // ReSharper disable once ConstantNullCoalescingCondition var job = protoMan.Index(highPriorityJob ?? SharedGameTicker.FallbackOverflowJob); - inventory.ClearAllSlotVisuals(); - - if (job.StartingGear != null) + if (job.StartingGear != null && invSystem.TryGetSlots(dummy, out var slots)) { var gear = protoMan.Index(job.StartingGear); - foreach (var slot in AllSlots) + foreach (var slot in slots) { - var itemType = gear.GetGear(slot, profile); + var itemType = gear.GetGear(slot.Name, profile); + if(invSystem.TryUnequip(dummy, slot.Name, out var unequippedItem, true, true)) + { + entMan.DeleteEntity(unequippedItem.Value); + } + if (itemType != string.Empty) { var item = entMan.SpawnEntity(itemType, MapCoordinates.Nullspace); - inventory.SetSlotVisuals(slot, item); - entMan.DeleteEntity(item); + invSystem.TryEquip(dummy, item, slot.Name, true, true); } } } diff --git a/Content.Client/Smoking/BurnStateVisualizer.cs b/Content.Client/Smoking/BurnStateVisualizer.cs index 71469bab90..f39290b294 100644 --- a/Content.Client/Smoking/BurnStateVisualizer.cs +++ b/Content.Client/Smoking/BurnStateVisualizer.cs @@ -46,17 +46,17 @@ namespace Content.Client.Smoking { case SmokableState.Lit: if (clothing != null) - clothing.ClothingEquippedPrefix = _litPrefix; + clothing.EquippedPrefix = _litPrefix; sprite.LayerSetState(0, _litIcon); break; case SmokableState.Burnt: if (clothing != null) - clothing.ClothingEquippedPrefix = _burntPrefix; + clothing.EquippedPrefix = _burntPrefix; sprite.LayerSetState(0, _burntIcon); break; case SmokableState.Unlit: if (clothing != null) - clothing.ClothingEquippedPrefix = _unlitPrefix; + clothing.EquippedPrefix = _unlitPrefix; sprite.LayerSetState(0, _unlitIcon); break; } diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index 61326e5be6..01b654bdf5 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; using Content.Server.Buckle.Components; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Shared.ActionBlocker; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Buckle.Components; +using Content.Shared.Item; using Content.Shared.Standing; using NUnit.Framework; using Robust.Shared.GameObjects; @@ -252,7 +252,7 @@ namespace Content.IntegrationTests.Tests.Buckle var akms = entityManager.SpawnEntity(ItemDummyId, coordinates); // Equip items - Assert.True(entityManager.TryGetComponent(akms, out ItemComponent item)); + Assert.True(entityManager.TryGetComponent(akms, out SharedItemComponent item)); Assert.True(hands.PutInHand(item)); } }); diff --git a/Content.IntegrationTests/Tests/DeleteInventoryTest.cs b/Content.IntegrationTests/Tests/DeleteInventoryTest.cs index 64e87cd90c..68898d6757 100644 --- a/Content.IntegrationTests/Tests/DeleteInventoryTest.cs +++ b/Content.IntegrationTests/Tests/DeleteInventoryTest.cs @@ -1,11 +1,13 @@ using System.Threading.Tasks; using Content.Server.Clothing.Components; -using Content.Server.Inventory.Components; +using Content.Server.Inventory; +using Content.Shared.Inventory; +using Content.Shared.Item; using NUnit.Framework; +using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.IntegrationTests.Tests { @@ -19,23 +21,25 @@ namespace Content.IntegrationTests.Tests { var server = StartServer(); - server.Assert(() => + await server.WaitAssertion(() => { // Spawn everything. var mapMan = IoCManager.Resolve(); + var invSystem = IoCManager.Resolve().GetEntitySystem(); mapMan.CreateNewMapEntity(MapId.Nullspace); var entMgr = IoCManager.Resolve(); var container = entMgr.SpawnEntity(null, MapCoordinates.Nullspace); - var inv = entMgr.AddComponent(container); + entMgr.AddComponent(container); + entMgr.AddComponent(container); var child = entMgr.SpawnEntity(null, MapCoordinates.Nullspace); - var item = entMgr.AddComponent(child); + var item = entMgr.AddComponent(child); item.SlotFlags = SlotFlags.HEAD; // Equip item. - Assert.That(inv.Equip(Slots.HEAD, item, false), Is.True); + Assert.That(invSystem.TryEquip(container, child, "head"), Is.True); // Delete parent. entMgr.DeleteEntity(container); @@ -43,8 +47,6 @@ namespace Content.IntegrationTests.Tests // Assert that child item was also deleted. Assert.That(item.Deleted, Is.True); }); - - await server.WaitIdleAsync(); } } } diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/ActionsComponentTests.cs b/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/ActionsComponentTests.cs index 8fc33251b6..61f92b49ab 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/ActionsComponentTests.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/ActionsComponentTests.cs @@ -3,19 +3,19 @@ using System.Linq; using System.Threading.Tasks; using Content.Client.Actions; using Content.Client.Actions.UI; +using Content.Client.Items.Components; using Content.Server.Actions; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Shared.Actions; using Content.Shared.Actions.Components; using Content.Shared.Actions.Prototypes; using Content.Shared.Cooldown; +using Content.Shared.Item; using NUnit.Framework; using Robust.Client.UserInterface; using Robust.Server.Player; using Robust.Shared; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -268,7 +268,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs // grant an extra item action, before pickup, initially disabled itemActions.GrantOrUpdate(ItemActionType.DebugToggle, false); - serverEntManager.GetComponent(serverPlayerEnt).PutInHand(serverEntManager.GetComponent(serverFlashlight), false); + serverEntManager.GetComponent(serverPlayerEnt).PutInHand(serverEntManager.GetComponent(serverFlashlight), false); // grant an extra item action, after pickup, with a cooldown itemActions.GrantOrUpdate(ItemActionType.DebugInstant, cooldown: cooldown); @@ -360,7 +360,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs { // pick the item up again, the states should be back to what they were when dropped, // as the states "stick" with the item - serverEntManager.GetComponent(serverPlayerEnt).PutInHand(serverEntManager.GetComponent(serverFlashlight), false); + serverEntManager.GetComponent(serverPlayerEnt).PutInHand(serverEntManager.GetComponent(serverFlashlight), false); Assert.That(serverActionsComponent.ItemActionStates().TryGetValue(serverFlashlight, out var lightStates)); Assert.That(lightStates.TryGetValue(ItemActionType.ToggleLight, out var lightState)); Assert.That(lightState.Equals(new ActionState(true, toggledOn: true))); diff --git a/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs b/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs index 98dfd08c07..06d5ced0de 100644 --- a/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs +++ b/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs @@ -1,18 +1,17 @@ using System.Threading.Tasks; -using Content.Server.Inventory.Components; +using Content.Server.Inventory; +using Content.Shared.Inventory; using NUnit.Framework; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.IntegrationTests.Tests { - // Tests the behavior of HumanInventoryControllerComponent. + // Tests the behavior of InventoryComponent. // i.e. the interaction between uniforms and the pocket/ID slots. // and also how big items don't fit in pockets. [TestFixture] - [TestOf(typeof(HumanInventoryControllerComponent))] public class HumanInventoryUniformSlotsTest : ContentIntegrationTest { private const string Prototypes = @" @@ -21,7 +20,7 @@ namespace Content.IntegrationTests.Tests id: HumanDummy components: - type: Inventory - - type: HumanInventoryController + - type: ContainerContainer - type: entity name: UniformDummy @@ -67,8 +66,11 @@ namespace Content.IntegrationTests.Tests EntityUid pocketItem = default; InventoryComponent inventory = null; + InventorySystem invSystem = default!; + server.Assert(() => { + invSystem = IoCManager.Resolve().GetEntitySystem(); var mapMan = IoCManager.Resolve(); mapMan.CreateNewMapEntity(MapId.Nullspace); @@ -81,26 +83,25 @@ namespace Content.IntegrationTests.Tests pocketItem = entityMan.SpawnEntity("FlashlightDummy", MapCoordinates.Nullspace); var tooBigItem = entityMan.SpawnEntity("ToolboxDummy", MapCoordinates.Nullspace); - inventory = entityMan.GetComponent(human); - Assert.That(inventory.CanEquip(Slots.INNERCLOTHING, uniform)); + Assert.That(invSystem.CanEquip(human, uniform, "jumpsuit", out _)); // Can't equip any of these since no uniform! - Assert.That(inventory.CanEquip(Slots.IDCARD, idCard), Is.False); - Assert.That(inventory.CanEquip(Slots.POCKET1, pocketItem), Is.False); - Assert.That(inventory.CanEquip(Slots.POCKET1, tooBigItem), Is.False); // This one fails either way. + Assert.That(invSystem.CanEquip(human, idCard, "id", out _), Is.False); + Assert.That(invSystem.CanEquip(human, pocketItem, "pocket1", out _), Is.False); + Assert.That(invSystem.CanEquip(human, tooBigItem, "pocket2", out _), Is.False); // This one fails either way. - inventory.Equip(Slots.INNERCLOTHING, uniform); + Assert.That(invSystem.TryEquip(human, uniform, "jumpsuit")); - Assert.That(inventory.Equip(Slots.IDCARD, idCard)); - Assert.That(inventory.Equip(Slots.POCKET1, pocketItem)); - Assert.That(inventory.CanEquip(Slots.POCKET1, tooBigItem), Is.False); // Still failing! + Assert.That(invSystem.TryEquip(human, idCard, "id")); + Assert.That(invSystem.CanEquip(human, tooBigItem, "pocket1", out _), Is.False); // Still failing! + Assert.That(invSystem.TryEquip(human, pocketItem, "pocket1")); Assert.That(IsDescendant(idCard, human)); Assert.That(IsDescendant(pocketItem, human)); // Now drop the jumpsuit. - inventory.Unequip(Slots.INNERCLOTHING); + Assert.That(invSystem.TryUnequip(human, "jumpsuit")); }); server.RunTicks(2); @@ -113,9 +114,9 @@ namespace Content.IntegrationTests.Tests Assert.That(IsDescendant(pocketItem, human), Is.False); // Ensure everything null here. - Assert.That(inventory.GetSlotItem(Slots.INNERCLOTHING), Is.Null); - Assert.That(inventory.GetSlotItem(Slots.IDCARD), Is.Null); - Assert.That(inventory.GetSlotItem(Slots.POCKET1), Is.Null); + Assert.That(!invSystem.TryGetSlotEntity(human, "jumpsuit", out _)); + Assert.That(!invSystem.TryGetSlotEntity(human, "id", out _)); + Assert.That(!invSystem.TryGetSlotEntity(human, "pocket1", out _)); }); await server.WaitIdleAsync(); diff --git a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs index 32088a0739..e9da8a5513 100644 --- a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs @@ -1,10 +1,11 @@ #nullable enable annotations using System.Threading.Tasks; +using Content.Client.Items.Components; using Content.Server.Hands.Components; using Content.Server.Interaction; -using Content.Server.Items; using Content.Shared.Hands.Components; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Weapons.Melee; using NUnit.Framework; using Robust.Shared.Containers; @@ -13,6 +14,7 @@ using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Reflection; +using ItemComponent = Content.Server.Clothing.Components.ItemComponent; namespace Content.IntegrationTests.Tests.Interaction.Click { @@ -97,7 +99,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click Assert.That(interactHand); Assert.That(sEntities.TryGetComponent(user, out var hands)); - Assert.That(hands.PutInHand(sEntities.GetComponent(item))); + Assert.That(hands.PutInHand(sEntities.GetComponent(item))); interactionSystem.UserInteraction(user, sEntities.GetComponent(target).Coordinates, target); Assert.That(interactUsing); @@ -169,7 +171,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click Assert.That(interactHand, Is.False); Assert.That(sEntities.TryGetComponent(user, out var hands)); - Assert.That(hands.PutInHand(sEntities.GetComponent(item))); + Assert.That(hands.PutInHand(sEntities.GetComponent(item))); interactionSystem.UserInteraction(user, sEntities.GetComponent(target).Coordinates, target); Assert.That(interactUsing, Is.False); @@ -238,7 +240,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click Assert.That(interactHand); Assert.That(sEntities.TryGetComponent(user, out var hands)); - Assert.That(hands.PutInHand(sEntities.GetComponent(item))); + Assert.That(hands.PutInHand(sEntities.GetComponent(item))); interactionSystem.UserInteraction(user, sEntities.GetComponent(target).Coordinates, target); Assert.That(interactUsing); @@ -308,7 +310,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click Assert.That(interactHand, Is.False); Assert.That(sEntities.TryGetComponent(user, out var hands)); - Assert.That(hands.PutInHand(sEntities.GetComponent(item))); + Assert.That(hands.PutInHand(sEntities.GetComponent(item))); interactionSystem.UserInteraction(user, sEntities.GetComponent(target).Coordinates, target); Assert.That(interactUsing, Is.False); @@ -393,7 +395,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click Assert.That(interactHand); Assert.That(sEntities.TryGetComponent(user, out var hands)); - Assert.That(hands.PutInHand(sEntities.GetComponent(item))); + Assert.That(hands.PutInHand(sEntities.GetComponent(item))); interactionSystem.UserInteraction(user, sEntities.GetComponent(target).Coordinates, target); Assert.That(interactUsing, Is.False); diff --git a/Content.IntegrationTests/Tests/InventoryHelpersTest.cs b/Content.IntegrationTests/Tests/InventoryHelpersTest.cs index bc7985020b..25d0d58f5d 100644 --- a/Content.IntegrationTests/Tests/InventoryHelpersTest.cs +++ b/Content.IntegrationTests/Tests/InventoryHelpersTest.cs @@ -1,19 +1,16 @@ using System; using System.Threading.Tasks; using Content.Server.Inventory; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Stunnable; +using Content.Shared.Inventory; using NUnit.Framework; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.IntegrationTests.Tests { [TestFixture] - [TestOf(typeof(InventoryHelpers))] public class InventoryHelpersTest : ContentIntegrationTest { private const string Prototypes = @" @@ -22,6 +19,7 @@ namespace Content.IntegrationTests.Tests id: InventoryStunnableDummy components: - type: Inventory + - type: ContainerContainer - type: StatusEffects allowed: - Stun @@ -53,43 +51,41 @@ namespace Content.IntegrationTests.Tests var sEntities = server.ResolveDependency(); - EntityUid human = default; - InventoryComponent inventory = null; - await server.WaitAssertion(() => { var mapMan = IoCManager.Resolve(); + var systemMan = IoCManager.Resolve(); mapMan.CreateNewMapEntity(MapId.Nullspace); - human = sEntities.SpawnEntity("InventoryStunnableDummy", MapCoordinates.Nullspace); - inventory = sEntities.GetComponent(human); + var human = sEntities.SpawnEntity("InventoryStunnableDummy", MapCoordinates.Nullspace); + var invSystem = systemMan.GetEntitySystem(); // Can't do the test if this human doesn't have the slots for it. - Assert.That(inventory.HasSlot(Slots.INNERCLOTHING)); - Assert.That(inventory.HasSlot(Slots.IDCARD)); + Assert.That(invSystem.HasSlot(human, "jumpsuit")); + Assert.That(invSystem.HasSlot(human, "id")); - Assert.That(inventory.SpawnItemInSlot(Slots.INNERCLOTHING, "InventoryJumpsuitJanitorDummy", true)); + Assert.That(invSystem.SpawnItemInSlot(human, "jumpsuit", "InventoryJumpsuitJanitorDummy", true)); // Do we actually have the uniform equipped? - Assert.That(inventory.TryGetSlotItem(Slots.INNERCLOTHING, out ItemComponent uniform)); - Assert.That(sEntities.GetComponent(uniform.Owner).EntityPrototype is + Assert.That(invSystem.TryGetSlotEntity(human, "jumpsuit", out var uniform)); + Assert.That(sEntities.GetComponent(uniform.Value).EntityPrototype is { ID: "InventoryJumpsuitJanitorDummy" }); - EntitySystem.Get().TryStun(human, TimeSpan.FromSeconds(1f), true); + systemMan.GetEntitySystem().TryStun(human, TimeSpan.FromSeconds(1f), true); // Since the mob is stunned, they can't equip this. - Assert.That(inventory.SpawnItemInSlot(Slots.IDCARD, "InventoryIDCardDummy", true), Is.False); + Assert.That(invSystem.SpawnItemInSlot(human, "id", "InventoryIDCardDummy", true), Is.False); // Make sure we don't have the ID card equipped. - Assert.That(inventory.TryGetSlotItem(Slots.IDCARD, out ItemComponent _), Is.False); + Assert.That(invSystem.TryGetSlotEntity(human, "item", out _), Is.False); // Let's try skipping the interaction check and see if it equips it! - Assert.That(inventory.SpawnItemInSlot(Slots.IDCARD, "InventoryIDCardDummy")); - Assert.That(inventory.TryGetSlotItem(Slots.IDCARD, out ItemComponent id)); - Assert.That(sEntities.GetComponent(id.Owner).EntityPrototype is + Assert.That(invSystem.SpawnItemInSlot(human, "id", "InventoryIDCardDummy", true, true)); + Assert.That(invSystem.TryGetSlotEntity(human, "id", out var idUid)); + Assert.That(sEntities.GetComponent(idUid.Value).EntityPrototype is { ID: "InventoryIDCardDummy" }); diff --git a/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs b/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs index 0ac5212b61..41d058c87c 100644 --- a/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs +++ b/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs @@ -1,11 +1,11 @@ using System.Linq; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.PDA; using Content.Shared.Access.Components; using Content.Shared.Containers.ItemSlots; +using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.PDA; using NUnit.Framework; using Robust.Server.Player; @@ -58,6 +58,8 @@ namespace Content.IntegrationTests.Tests.PDA var sPlayerManager = server.ResolveDependency(); var sEntityManager = server.ResolveDependency(); + var invSystem = server.ResolveDependency().GetEntitySystem(); + await server.WaitAssertion(() => { var player = sPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault(); @@ -71,7 +73,7 @@ namespace Content.IntegrationTests.Tests.PDA // Put PDA in hand var dummyPda = sEntityManager.SpawnEntity(PdaDummy, sEntityManager.GetComponent(player).MapPosition); - var pdaItemComponent = sEntityManager.GetComponent(dummyPda); + var pdaItemComponent = sEntityManager.GetComponent(dummyPda); sEntityManager.GetComponent(player).PutInHand(pdaItemComponent); var pdaComponent = sEntityManager.GetComponent(dummyPda); @@ -91,7 +93,7 @@ namespace Content.IntegrationTests.Tests.PDA // Put ID card in hand var idDummy = sEntityManager.SpawnEntity(IdCardDummy, sEntityManager.GetComponent(player).MapPosition); - var idItemComponent = sEntityManager.GetComponent(idDummy); + var idItemComponent = sEntityManager.GetComponent(idDummy); sEntityManager.GetComponent(player).PutInHand(idItemComponent); var idCardComponent = sEntityManager.GetComponent(idDummy); @@ -103,20 +105,16 @@ namespace Content.IntegrationTests.Tests.PDA Assert.That(id, Is.EqualTo(idCardComponent)); // Remove all IDs and PDAs - var inventory = sEntityManager.GetComponent(player); + Assert.That(invSystem.TryGetSlots(player, out var slots)); - foreach (var slot in inventory.Slots) + foreach (var slot in slots) { - var item = inventory.GetSlotItem(slot); - - if (item == null) - { + if(!invSystem.TryGetSlotEntity(player, slot.Name, out var item)) continue; - } - if (sEntityManager.HasComponent(item.Owner)) + if (sEntityManager.HasComponent(item)) { - inventory.ForceUnequip(slot); + invSystem.TryUnequip(player, slot.Name, force: true); } } diff --git a/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs b/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs index 5def6d3f43..f6e636bc2c 100644 --- a/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs +++ b/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs @@ -1,7 +1,7 @@ using Content.Server.Hands.Components; using Content.Server.Interaction; -using Content.Server.Items; using Content.Shared.Interaction.Helpers; +using Content.Shared.Item; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -25,7 +25,7 @@ namespace Content.Server.AI.Operators.Inventory var entMan = IoCManager.Resolve(); if (entMan.Deleted(_target) - || !entMan.HasComponent(_target) + || !entMan.HasComponent(_target) || _target.IsInContainer() || !_owner.InRangeUnobstructed(_target, popup: true)) { diff --git a/Content.Server/AI/Operators/Inventory/UseItemInInventoryOperator.cs b/Content.Server/AI/Operators/Inventory/UseItemInInventoryOperator.cs index 1670277b61..db584ea2a4 100644 --- a/Content.Server/AI/Operators/Inventory/UseItemInInventoryOperator.cs +++ b/Content.Server/AI/Operators/Inventory/UseItemInInventoryOperator.cs @@ -1,5 +1,5 @@ using Content.Server.Hands.Components; -using Content.Server.Items; +using Content.Shared.Item; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -29,7 +29,7 @@ namespace Content.Server.AI.Operators.Inventory return Outcome.Failed; } - if (!entMan.TryGetComponent(_target, out ItemComponent? itemComponent)) + if (!entMan.TryGetComponent(_target, out SharedItemComponent? itemComponent)) { return Outcome.Failed; } diff --git a/Content.Server/AI/Operators/Nutrition/UseDrinkInInventoryOperator.cs b/Content.Server/AI/Operators/Nutrition/UseDrinkInInventoryOperator.cs index 6c3100b4f8..9990db6c54 100644 --- a/Content.Server/AI/Operators/Nutrition/UseDrinkInInventoryOperator.cs +++ b/Content.Server/AI/Operators/Nutrition/UseDrinkInInventoryOperator.cs @@ -1,7 +1,7 @@ using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Nutrition.Components; using Content.Server.Nutrition.EntitySystems; +using Content.Shared.Item; using Content.Shared.Nutrition.Components; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -34,7 +34,7 @@ namespace Content.Server.AI.Operators.Nutrition // TODO: Also have this check storage a la backpack etc. if (entities.Deleted(_target) || !entities.TryGetComponent(_owner, out HandsComponent? handsComponent) || - !entities.TryGetComponent(_target, out ItemComponent? itemComponent)) + !entities.TryGetComponent(_target, out SharedItemComponent? itemComponent)) { return Outcome.Failed; } diff --git a/Content.Server/AI/Operators/Nutrition/UseFoodInInventoryOperator.cs b/Content.Server/AI/Operators/Nutrition/UseFoodInInventoryOperator.cs index 41c940477e..279a6b3d71 100644 --- a/Content.Server/AI/Operators/Nutrition/UseFoodInInventoryOperator.cs +++ b/Content.Server/AI/Operators/Nutrition/UseFoodInInventoryOperator.cs @@ -1,6 +1,6 @@ using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Nutrition.Components; +using Content.Shared.Item; using Content.Shared.Nutrition.Components; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -33,7 +33,7 @@ namespace Content.Server.AI.Operators.Nutrition // TODO: Also have this check storage a la backpack etc. if (entities.Deleted(_target) || !entities.TryGetComponent(_owner, out HandsComponent? handsComponent) || - !entities.TryGetComponent(_target, out ItemComponent? itemComponent)) + !entities.TryGetComponent(_target, out SharedItemComponent? itemComponent)) { return Outcome.Failed; } diff --git a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs index 2b20a2b3e7..3717d90563 100644 --- a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs +++ b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs @@ -10,7 +10,7 @@ namespace Content.Server.AI.Utility.Considerations.Clothing { public sealed class ClothingInInventoryCon : Consideration { - public ClothingInInventoryCon Slot(EquipmentSlotDefines.SlotFlags slotFlags, Blackboard context) + public ClothingInInventoryCon Slot(SlotFlags slotFlags, Blackboard context) { // Ideally we'd just use a variable but then if we were iterating through multiple AI at once it'd be // Stuffed so we need to store it on the AI's context. @@ -21,16 +21,17 @@ namespace Content.Server.AI.Utility.Considerations.Clothing protected override float GetScore(Blackboard context) { var slots = context.GetState().GetValue(); - var slotFlags = EquipmentSlotDefines.SlotMasks[slots]; + if (slots == null) return 0.0f; foreach (var entity in context.GetState().GetValue()) { - if (!IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothingComponent)) + if (!IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothingComponent) || + !EntitySystem.Get().TryGetSlot(entity, slots, out var slotDef)) { continue; } - if ((clothingComponent.SlotFlags & slotFlags) != 0) + if ((clothingComponent.SlotFlags & slotDef.SlotFlags) != 0) { return 1.0f; } diff --git a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs index 57ddb53e70..e28105b41d 100644 --- a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs +++ b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs @@ -7,7 +7,7 @@ namespace Content.Server.AI.Utility.Considerations.Clothing public class ClothingInSlotCon : Consideration { - public ClothingInSlotCon Slot(EquipmentSlotDefines.Slots slot, Blackboard context) + public ClothingInSlotCon Slot(string slot, Blackboard context) { context.GetState().SetValue(slot); return this; @@ -17,7 +17,7 @@ namespace Content.Server.AI.Utility.Considerations.Clothing { var slot = context.GetState().GetValue(); var inventory = context.GetState().GetValue(); - return inventory.ContainsKey(slot) ? 1.0f : 0.0f; + return slot != null && inventory.ContainsKey(slot) ? 1.0f : 0.0f; } } } diff --git a/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInInventoryCon.cs b/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInInventoryCon.cs index 14ccfbf4d2..8c4783efdb 100644 --- a/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInInventoryCon.cs +++ b/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInInventoryCon.cs @@ -2,7 +2,7 @@ using Content.Server.AI.WorldState; using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States.Hands; using Content.Server.AI.WorldState.States.Inventory; -using Content.Server.Items; +using Content.Shared.Item; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -16,7 +16,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory // If not then check if we have a free hand var target = context.GetState().GetValue(); - if (target == null || !IoCManager.Resolve().HasComponent(target)) + if (target == null || !IoCManager.Resolve().HasComponent(target)) { return 0.0f; } diff --git a/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs b/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs index b7fcd97b1c..92d5d4b23f 100644 --- a/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs +++ b/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs @@ -1,7 +1,7 @@ using Content.Server.AI.WorldState; using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States.Inventory; -using Content.Server.Items; +using Content.Shared.Item; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -13,7 +13,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory { var target = context.GetState().GetValue(); - if (target == null || !IoCManager.Resolve().HasComponent(target)) + if (target == null || !IoCManager.Resolve().HasComponent(target)) { return 0.0f; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs index e570698cc6..9ccd12744c 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs @@ -27,7 +27,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves return new [] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.GLOVES, context) + considerationsManager.Get().Slot("gloves", context) .InverseBoolCurve(context), }; } @@ -39,7 +39,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0) + (clothing.SlotFlags & SlotFlags.GLOVES) != 0) { yield return new EquipGloves {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/PickUpAnyNearbyGlovesExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/PickUpAnyNearbyGlovesExp.cs index 959a4a6d87..ed034fe91f 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/PickUpAnyNearbyGlovesExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/PickUpAnyNearbyGlovesExp.cs @@ -23,9 +23,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves var considerationsManager = IoCManager.Resolve(); return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.GLOVES, context) + considerationsManager.Get().Slot("gloves", context) .InverseBoolCurve(context), - considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.GLOVES, context) + considerationsManager.Get().Slot(SlotFlags.GLOVES, context) .InverseBoolCurve(context), }; } @@ -37,7 +37,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0) + (clothing.SlotFlags & SlotFlags.GLOVES) != 0) { yield return new PickUpGloves {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs index 62f675ae1c..f09527387b 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs @@ -26,7 +26,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head var considerationsManager = IoCManager.Resolve(); return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.HEAD, context) + considerationsManager.Get().Slot("head", context) .InverseBoolCurve(context), }; } @@ -38,7 +38,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0) + (clothing.SlotFlags & SlotFlags.HEAD) != 0) { yield return new EquipHead {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs index 0e1ad0e81c..4367ceaad7 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs @@ -23,9 +23,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head var considerationsManager = IoCManager.Resolve(); return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.HEAD, context) + considerationsManager.Get().Slot("head", context) .InverseBoolCurve(context), - considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.HEAD, context) + considerationsManager.Get().Slot(SlotFlags.HEAD, context) .InverseBoolCurve(context) }; } @@ -37,7 +37,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0) + (clothing.SlotFlags & SlotFlags.HEAD) != 0) { yield return new PickUpHead {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs index 88fc7d3cf3..930b8f8007 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs @@ -27,7 +27,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context) + considerationsManager.Get().Slot("outerClothing", context) .InverseBoolCurve(context), }; } @@ -39,7 +39,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0) + (clothing.SlotFlags & SlotFlags.OUTERCLOTHING) != 0) { yield return new EquipOuterClothing {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/PickUpAnyNearbyOuterClothingExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/PickUpAnyNearbyOuterClothingExp.cs index 3134bd14d3..b6016d304f 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/PickUpAnyNearbyOuterClothingExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/PickUpAnyNearbyOuterClothingExp.cs @@ -24,9 +24,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context) + considerationsManager.Get().Slot("outerClothing", context) .InverseBoolCurve(context), - considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.OUTERCLOTHING, context) + considerationsManager.Get().Slot(SlotFlags.OUTERCLOTHING, context) .InverseBoolCurve(context) }; } @@ -38,7 +38,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0) + (clothing.SlotFlags & SlotFlags.OUTERCLOTHING) != 0) { yield return new PickUpOuterClothing {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs index 85077d611c..15ab7d4c08 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs @@ -27,7 +27,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.SHOES, context) + considerationsManager.Get().Slot("shoes", context) .InverseBoolCurve(context), }; } @@ -39,7 +39,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0) + (clothing.SlotFlags & SlotFlags.FEET) != 0) { yield return new EquipShoes {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/PickUpAnyNearbyShoesExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/PickUpAnyNearbyShoesExp.cs index dca91f730d..597c1946fe 100644 --- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/PickUpAnyNearbyShoesExp.cs +++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/PickUpAnyNearbyShoesExp.cs @@ -24,9 +24,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes return new[] { - considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.SHOES, context) + considerationsManager.Get().Slot("shoes", context) .InverseBoolCurve(context), - considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.SHOES, context) + considerationsManager.Get().Slot(SlotFlags.FEET, context) .InverseBoolCurve(context) }; } @@ -38,7 +38,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes foreach (var entity in context.GetState().GetValue()) { if (IoCManager.Resolve().TryGetComponent(entity, out ClothingComponent? clothing) && - (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0) + (clothing.SlotFlags & SlotFlags.FEET) != 0) { yield return new PickUpShoes {Owner = owner, Target = entity, Bonus = Bonus}; } diff --git a/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs index 768bfc0a31..92cfc38d5e 100644 --- a/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs +++ b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs @@ -1,13 +1,11 @@ -using Content.Shared.Inventory; - namespace Content.Server.AI.WorldState.States.Clothing { - public sealed class ClothingSlotConState : PlanningStateData + public sealed class ClothingSlotConState : PlanningStateData { public override string Name => "ClothingSlotCon"; public override void Reset() { - Value = EquipmentSlotDefines.Slots.NONE; + Value = ""; } } } diff --git a/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs index 9e48eec82d..7951d57e0c 100644 --- a/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs +++ b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs @@ -2,12 +2,12 @@ using Content.Shared.Inventory; namespace Content.Server.AI.WorldState.States.Clothing { - public sealed class ClothingSlotFlagConState : PlanningStateData + public sealed class ClothingSlotFlagConState : PlanningStateData { public override string Name => "ClothingSlotFlagCon"; public override void Reset() { - Value = EquipmentSlotDefines.SlotFlags.NONE; + Value = SlotFlags.NONE; } } } diff --git a/Content.Server/AI/WorldState/States/Clothing/EquippedClothingState.cs b/Content.Server/AI/WorldState/States/Clothing/EquippedClothingState.cs index 695dc524a9..7c4498961a 100644 --- a/Content.Server/AI/WorldState/States/Clothing/EquippedClothingState.cs +++ b/Content.Server/AI/WorldState/States/Clothing/EquippedClothingState.cs @@ -1,34 +1,35 @@ using System.Collections.Generic; -using Content.Server.Inventory.Components; using Content.Shared.Inventory; using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using InventoryComponent = Content.Shared.Inventory.InventoryComponent; namespace Content.Server.AI.WorldState.States.Clothing { [UsedImplicitly] - public sealed class EquippedClothingState : StateData> + public sealed class EquippedClothingState : StateData> { public override string Name => "EquippedClothing"; - public override Dictionary GetValue() + public override Dictionary GetValue() { - var result = new Dictionary(); + var result = new Dictionary(); - if (!IoCManager.Resolve().TryGetComponent(Owner, out InventoryComponent? inventoryComponent)) + var invSystem = EntitySystem.Get(); + if (!invSystem.TryGetSlots(Owner, out var slotDefinitions)) { return result; } - foreach (var slot in EquipmentSlotDefines.AllSlots) + foreach (var slot in slotDefinitions) { - if (!inventoryComponent.HasSlot(slot)) continue; - var slotItem = inventoryComponent.GetSlotItem(slot); + if (!invSystem.HasSlot(Owner, slot.Name)) continue; - if (slotItem != null) + if (invSystem.TryGetSlotEntity(Owner, slot.Name, out var entityUid)) { - result.Add(slot, slotItem.Owner); + result.Add(slot.Name, entityUid.Value); } } diff --git a/Content.Server/AME/Components/AMEControllerComponent.cs b/Content.Server/AME/Components/AMEControllerComponent.cs index 7504c4971c..913f0effe6 100644 --- a/Content.Server/AME/Components/AMEControllerComponent.cs +++ b/Content.Server/AME/Components/AMEControllerComponent.cs @@ -2,13 +2,13 @@ using System; using System.Linq; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.NodeContainer; using Content.Server.Power.Components; using Content.Server.UserInterface; using Content.Shared.ActionBlocker; using Content.Shared.AME; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Sound; using Robust.Server.GameObjects; @@ -245,7 +245,7 @@ namespace Content.Server.AME.Components _jarSlot.Remove(jar); UpdateUserInterface(); - if (!_entities.TryGetComponent(user, out var hands) || !_entities.TryGetComponent(jar, out var item)) + if (!_entities.TryGetComponent(user, out var hands) || !_entities.TryGetComponent(jar, out var item)) return; if (hands.CanPutInHand(item)) hands.PutInHand(item); diff --git a/Content.Server/Access/Systems/IdCardSystem.cs b/Content.Server/Access/Systems/IdCardSystem.cs index 01ebef2251..364a53d7ec 100644 --- a/Content.Server/Access/Systems/IdCardSystem.cs +++ b/Content.Server/Access/Systems/IdCardSystem.cs @@ -1,18 +1,19 @@ -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Shared.Hands.Components; using Content.Shared.Inventory; -using Content.Shared.PDA; using Robust.Shared.GameObjects; using Robust.Shared.Localization; using System.Diagnostics.CodeAnalysis; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; +using Content.Shared.PDA; +using Robust.Shared.IoC; namespace Content.Server.Access.Systems { public class IdCardSystem : SharedIdCardSystem { + [Dependency] private readonly InventorySystem _inventorySystem = default!; + public override void Initialize() { base.Initialize(); @@ -101,7 +102,12 @@ namespace Content.Server.Access.Systems return true; // check inventory slot? - return TryGetIdCardSlot(uid, out idCard); + if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && TryGetIdCard(idUid.Value, out idCard)) + { + return true; + } + + return false; } /// @@ -121,17 +127,5 @@ namespace Content.Server.Access.Systems return false; } - - /// - /// Try get id card from mobs ID inventory slot - /// - public bool TryGetIdCardSlot(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard) - { - idCard = null; - return EntityManager.TryGetComponent(uid, out InventoryComponent? inventoryComponent) && - inventoryComponent.HasSlot(EquipmentSlotDefines.Slots.IDCARD) && - inventoryComponent.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item) && - TryGetIdCard(item.Owner, out idCard); - } } } diff --git a/Content.Server/Actions/Spells/GiveItemSpell.cs b/Content.Server/Actions/Spells/GiveItemSpell.cs index 7c3f0712f5..cd916e7a90 100644 --- a/Content.Server/Actions/Spells/GiveItemSpell.cs +++ b/Content.Server/Actions/Spells/GiveItemSpell.cs @@ -1,9 +1,9 @@ using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Popups; using Content.Shared.ActionBlocker; using Content.Shared.Actions.Behaviors; using Content.Shared.Cooldown; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Sound; using JetBrains.Annotations; @@ -57,9 +57,9 @@ namespace Content.Server.Actions.Spells // TODO: Look this is shitty and ideally a test would do it var spawnedProto = entMan.SpawnEntity(ItemProto, entMan.GetComponent(caster).MapPosition); - if (!entMan.TryGetComponent(spawnedProto, out ItemComponent? itemComponent)) + if (!entMan.TryGetComponent(spawnedProto, out SharedItemComponent? itemComponent)) { - Logger.Error($"Tried to use {nameof(GiveItemSpell)} but prototype has no {nameof(ItemComponent)}?"); + Logger.Error($"Tried to use {nameof(GiveItemSpell)} but prototype has no {nameof(SharedItemComponent)}?"); entMan.DeleteEntity(spawnedProto); return; } diff --git a/Content.Server/Administration/AdminVerbSystem.cs b/Content.Server/Administration/AdminVerbSystem.cs index 47a866fa31..0d170434ef 100644 --- a/Content.Server/Administration/AdminVerbSystem.cs +++ b/Content.Server/Administration/AdminVerbSystem.cs @@ -10,7 +10,7 @@ using Content.Server.Disposal.Tube.Components; using Content.Server.EUI; using Content.Server.Explosion.EntitySystems; using Content.Server.Ghost.Roles; -using Content.Server.Inventory.Components; +using Content.Server.Inventory; using Content.Server.Mind.Commands; using Content.Server.Mind.Components; using Content.Server.Players; @@ -19,6 +19,7 @@ using Content.Shared.Body.Components; using Content.Shared.Database; using Content.Shared.GameTicking; using Content.Shared.Interaction.Helpers; +using Content.Shared.Inventory; using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Server.Console; diff --git a/Content.Server/Administration/Commands/SetOutfitCommand.cs b/Content.Server/Administration/Commands/SetOutfitCommand.cs index 31c3891a4b..187cf7e30b 100644 --- a/Content.Server/Administration/Commands/SetOutfitCommand.cs +++ b/Content.Server/Administration/Commands/SetOutfitCommand.cs @@ -1,7 +1,5 @@ using Content.Server.Administration.UI; using Content.Server.EUI; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Preferences.Managers; using Content.Shared.Administration; using Content.Shared.Inventory; @@ -15,6 +13,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Prototypes; +using InventoryComponent = Content.Shared.Inventory.InventoryComponent; namespace Content.Server.Administration.Commands { @@ -88,23 +87,27 @@ namespace Content.Server.Administration.Commands profile = prefs.SelectedCharacter as HumanoidCharacterProfile; } - foreach (var slot in inventoryComponent.Slots) + var invSystem = EntitySystem.Get(); + if (invSystem.TryGetSlots(target, out var slotDefinitions, inventoryComponent)) { - inventoryComponent.ForceUnequip(slot); - var gearStr = startingGear.GetGear(slot, profile); - if (gearStr == string.Empty) + foreach (var slot in slotDefinitions) { - continue; - } - var equipmentEntity = entityManager.SpawnEntity(gearStr, entityManager.GetComponent(target).Coordinates); - if (slot == EquipmentSlotDefines.Slots.IDCARD && - entityManager.TryGetComponent(equipmentEntity, out var pdaComponent) && - pdaComponent.ContainedID != null) - { - pdaComponent.ContainedID.FullName = entityManager.GetComponent(target).EntityName; - } + invSystem.TryUnequip(target, slot.Name, true, true, inventoryComponent); + var gearStr = startingGear.GetGear(slot.Name, profile); + if (gearStr == string.Empty) + { + continue; + } + var equipmentEntity = entityManager.SpawnEntity(gearStr, entityManager.GetComponent(target).Coordinates); + if (slot.Name == "id" && + entityManager.TryGetComponent(equipmentEntity, out var pdaComponent) && + pdaComponent.ContainedID != null) + { + pdaComponent.ContainedID.FullName = entityManager.GetComponent(target).EntityName; + } - inventoryComponent.Equip(slot, entityManager.GetComponent(equipmentEntity), false); + invSystem.TryEquip(target, equipmentEntity, slot.Name, true, inventory: inventoryComponent); + } } } } diff --git a/Content.Server/Atmos/Components/BreathToolComponent.cs b/Content.Server/Atmos/Components/BreathToolComponent.cs index 326e45ad62..bee6c4c662 100644 --- a/Content.Server/Atmos/Components/BreathToolComponent.cs +++ b/Content.Server/Atmos/Components/BreathToolComponent.cs @@ -1,5 +1,7 @@ using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Shared.Inventory; +using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization.Manager.Attributes; @@ -10,7 +12,7 @@ namespace Content.Server.Atmos.Components /// Used in internals as breath tool. /// [RegisterComponent] - public class BreathToolComponent : Component, IEquipped, IUnequipped + public class BreathToolComponent : Component { [Dependency] private readonly IEntityManager _entities = default!; @@ -18,11 +20,11 @@ namespace Content.Server.Atmos.Components /// Tool is functional only in allowed slots /// [DataField("allowedSlots")] - private EquipmentSlotDefines.SlotFlags _allowedSlots = EquipmentSlotDefines.SlotFlags.MASK; + public SlotFlags AllowedSlots = SlotFlags.MASK; public override string Name => "BreathMask"; - public bool IsFunctional { get; private set; } - public EntityUid ConnectedInternalsEntity { get; private set; } + public bool IsFunctional; + public EntityUid ConnectedInternalsEntity; protected override void Shutdown() { @@ -30,23 +32,6 @@ namespace Content.Server.Atmos.Components DisconnectInternals(); } - void IEquipped.Equipped(EquippedEventArgs eventArgs) - { - if ((EquipmentSlotDefines.SlotMasks[eventArgs.Slot] & _allowedSlots) != _allowedSlots) return; - IsFunctional = true; - - if (_entities.TryGetComponent(eventArgs.User, out InternalsComponent? internals)) - { - ConnectedInternalsEntity = eventArgs.User; - internals.ConnectBreathTool(Owner); - } - } - - void IUnequipped.Unequipped(UnequippedEventArgs eventArgs) - { - DisconnectInternals(); - } - public void DisconnectInternals() { var old = ConnectedInternalsEntity; diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs index c68392d01b..9714875512 100644 --- a/Content.Server/Body/Systems/LungSystem.cs +++ b/Content.Server/Body/Systems/LungSystem.cs @@ -7,6 +7,7 @@ using Content.Server.Popups; using Content.Shared.Atmos; using Content.Shared.Body.Components; using Content.Shared.Body.Events; +using Content.Shared.Inventory.Events; using Content.Shared.MobState.Components; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -27,6 +28,26 @@ public class LungSystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(OnAddedToBody); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); + } + + private void OnGotUnequipped(EntityUid uid, BreathToolComponent component, GotUnequippedEvent args) + { + component.DisconnectInternals(); + } + + private void OnGotEquipped(EntityUid uid, BreathToolComponent component, GotEquippedEvent args) + { + + if ((args.SlotFlags & component.AllowedSlots) != component.AllowedSlots) return; + component.IsFunctional = true; + + if (TryComp(args.Equipee, out InternalsComponent? internals)) + { + component.ConnectedInternalsEntity = args.Equipee; + internals.ConnectBreathTool(uid); + } } private void OnAddedToBody(EntityUid uid, LungComponent component, AddedToBodyEvent args) diff --git a/Content.Server/Chat/Commands/SuicideCommand.cs b/Content.Server/Chat/Commands/SuicideCommand.cs index dcf236b1cc..2086594f98 100644 --- a/Content.Server/Chat/Commands/SuicideCommand.cs +++ b/Content.Server/Chat/Commands/SuicideCommand.cs @@ -1,17 +1,16 @@ using System.Linq; using Content.Server.Act; -using Content.Server.Administration; using Content.Server.Administration.Logs; using Content.Server.Chat.Managers; using Content.Server.GameTicking; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Players; using Content.Server.Popups; using Content.Shared.Administration; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Database; +using Content.Shared.Item; using Content.Shared.Popups; using Robust.Server.Player; using Robust.Shared.Console; @@ -108,7 +107,7 @@ namespace Content.Server.Chat.Commands { foreach (var entity in entities) { - if (_entities.HasComponent(entity)) + if (_entities.HasComponent(entity)) continue; var suicide = _entities.GetComponents(entity).FirstOrDefault(); if (suicide != null) diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 02cb35f2f4..d167487f97 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -3,8 +3,6 @@ using System.Linq; using Content.Server.Administration.Managers; using Content.Server.Ghost.Components; using Content.Server.Headset; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.MoMMI; using Content.Server.Preferences.Managers; using Content.Server.Radio.EntitySystems; @@ -171,9 +169,10 @@ namespace Content.Server.Chat.Managers message = message[0].ToString().ToUpper() + message.Remove(0, 1); - if (_entManager.TryGetComponent(source, out InventoryComponent? inventory) && - inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.EARS, out ItemComponent? item) && - _entManager.TryGetComponent(item.Owner, out HeadsetComponent? headset)) + var invSystem = EntitySystem.Get(); + + if (invSystem.TryGetSlotEntity(source, "ears", out var entityUid) && + _entManager.TryGetComponent(entityUid, out HeadsetComponent? headset)) { headset.RadioRequested = true; } diff --git a/Content.Server/Chemistry/Components/ChemMasterComponent.cs b/Content.Server/Chemistry/Components/ChemMasterComponent.cs index dee840b3e4..da4ebab6be 100644 --- a/Content.Server/Chemistry/Components/ChemMasterComponent.cs +++ b/Content.Server/Chemistry/Components/ChemMasterComponent.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Labels.Components; using Content.Server.Power.Components; using Content.Server.UserInterface; @@ -12,6 +11,7 @@ using Content.Shared.Chemistry.Components; using Content.Shared.Containers.ItemSlots; using Content.Shared.FixedPoint; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Random.Helpers; using Content.Shared.Sound; @@ -319,7 +319,7 @@ namespace Content.Server.Chemistry.Components //Try to give them the bottle if (_entities.TryGetComponent(user, out var hands) && - _entities.TryGetComponent(bottle, out var item)) + _entities.TryGetComponent(bottle, out var item)) { if (hands.CanPutInHand(item)) { @@ -368,7 +368,7 @@ namespace Content.Server.Chemistry.Components //Try to give them the bottle if (_entities.TryGetComponent(user, out var hands) && - _entities.TryGetComponent(pill, out var item)) + _entities.TryGetComponent(pill, out var item)) { if (hands.CanPutInHand(item)) { diff --git a/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs index 8599d5d773..367be9bb0c 100644 --- a/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs +++ b/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs @@ -1,8 +1,6 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Shared.FixedPoint; using Content.Shared.Foam; using Content.Shared.Inventory; @@ -40,20 +38,22 @@ namespace Content.Server.Chemistry.Components if (!_entMan.TryGetComponent(entity, out BloodstreamComponent? bloodstream)) return; + var invSystem = EntitySystem.Get(); + // TODO: Add a permeability property to clothing // For now it just adds to protection for each clothing equipped var protection = 0f; - if (_entMan.TryGetComponent(entity, out InventoryComponent? inventory)) + if (invSystem.TryGetSlots(entity, out var slotDefinitions)) { - foreach (var slot in inventory.Slots) + foreach (var slot in slotDefinitions) { - if (slot == EquipmentSlotDefines.Slots.BACKPACK || - slot == EquipmentSlotDefines.Slots.POCKET1 || - slot == EquipmentSlotDefines.Slots.POCKET2 || - slot == EquipmentSlotDefines.Slots.IDCARD) + if (slot.Name == "back" || + slot.Name == "pocket1" || + slot.Name == "pocket2" || + slot.Name == "id") continue; - if (inventory.TryGetSlotItem(slot, out ItemComponent? _)) + if (invSystem.TryGetSlotEntity(entity, slot.Name, out _)) protection += 0.025f; } } diff --git a/Content.Server/Clothing/Components/ClothingComponent.cs b/Content.Server/Clothing/Components/ClothingComponent.cs index 101af363e8..48c8721f26 100644 --- a/Content.Server/Clothing/Components/ClothingComponent.cs +++ b/Content.Server/Clothing/Components/ClothingComponent.cs @@ -1,94 +1,67 @@ using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Shared.Clothing; using Content.Shared.Interaction; +using Content.Shared.Inventory; using Content.Shared.Item; -using Content.Shared.Popups; -using Content.Shared.Sound; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.IoC; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Server.Clothing.Components { [RegisterComponent] [ComponentReference(typeof(SharedItemComponent))] - [ComponentReference(typeof(ItemComponent))] - [NetworkedComponent()] + public class ItemComponent : SharedItemComponent{} + + [RegisterComponent] + [NetworkedComponent] + [ComponentReference(typeof(SharedItemComponent))] public class ClothingComponent : ItemComponent, IUse { [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; public override string Name => "Clothing"; - [ViewVariables] - [DataField("Slots")] - public SlotFlags SlotFlags = SlotFlags.PREVENTEQUIP; //Different from None, NONE allows equips if no slot flags are required - [DataField("QuickEquip")] private bool _quickEquipEnabled = true; [DataField("HeatResistance")] private int _heatResistance = 323; - [DataField("EquipSound")] - public SoundSpecifier? EquipSound { get; set; } = default!; - [ViewVariables(VVAccess.ReadWrite)] public int HeatResistance => _heatResistance; - [DataField("ClothingPrefix")] - private string? _clothingEquippedPrefix; - [ViewVariables(VVAccess.ReadWrite)] - public string? ClothingEquippedPrefix - { - get => _clothingEquippedPrefix; - set - { - Dirty(); - _clothingEquippedPrefix = value; - } - } - - public override ComponentState GetComponentState() - { - return new ClothingComponentState(ClothingEquippedPrefix, EquippedPrefix); - } - bool IUse.UseEntity(UseEntityEventArgs eventArgs) { if (!_quickEquipEnabled) return false; + + var invSystem = EntitySystem.Get(); if (!_entities.TryGetComponent(eventArgs.User, out InventoryComponent? inv) - || !_entities.TryGetComponent(eventArgs.User, out HandsComponent? hands)) return false; + || !_entities.TryGetComponent(eventArgs.User, out HandsComponent? hands) || !_prototype.TryIndex(inv.TemplateId, out var prototype)) return false; - foreach (var (slot, flag) in SlotMasks) + foreach (var slotDef in prototype.Slots) { - // We check if the clothing can be equipped in this slot. - if ((SlotFlags & flag) == 0) continue; + if(!invSystem.CanEquip(eventArgs.User, Owner, slotDef.Name, out _, slotDef, inv)) + continue; - if (inv.TryGetSlotItem(slot, out ItemComponent? item)) + if (invSystem.TryGetSlotEntity(eventArgs.User, slotDef.Name, out var slotEntity, inv)) { - if (!inv.CanUnequip(slot)) continue; - hands.Drop(Owner); - inv.Unequip(slot); - hands.PutInHand(item); + if(!invSystem.TryUnequip(eventArgs.User, slotDef.Name, true, inventory: inv)) + continue; - if (!TryEquip(inv, slot, eventArgs.User)) - { - hands.Drop(item.Owner); - inv.Equip(slot, item); - hands.PutInHand(_entities.GetComponent(Owner)); - } + if (!invSystem.TryEquip(eventArgs.User, Owner, slotDef.Name, true, inventory: inv)) + continue; + + hands.PutInHandOrDrop(slotEntity.Value); } else { - hands.Drop(Owner); - if (!TryEquip(inv, slot, eventArgs.User)) - hands.PutInHand(_entities.GetComponent(Owner)); + if (!invSystem.TryEquip(eventArgs.User, Owner, slotDef.Name, true, inventory: inv)) + continue; } return true; @@ -96,18 +69,5 @@ namespace Content.Server.Clothing.Components return false; } - - public bool TryEquip(InventoryComponent inv, Slots slot, EntityUid user) - { - if (!inv.Equip(slot, this, true, out var reason)) - { - if (reason != null) - Owner.PopupMessage(user, reason); - - return false; - } - - return true; - } } } diff --git a/Content.Server/Clothing/Components/MagbootsComponent.cs b/Content.Server/Clothing/Components/MagbootsComponent.cs index a0e19db7cc..efc1980ce1 100644 --- a/Content.Server/Clothing/Components/MagbootsComponent.cs +++ b/Content.Server/Clothing/Components/MagbootsComponent.cs @@ -1,7 +1,5 @@ using Content.Server.Alert; using Content.Server.Atmos.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Shared.Actions; using Content.Shared.Actions.Behaviors.Item; using Content.Shared.Actions.Components; @@ -9,6 +7,7 @@ using Content.Shared.Alert; using Content.Shared.Clothing; using Content.Shared.Interaction; using Content.Shared.Inventory; +using Content.Shared.Item; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Containers; @@ -16,15 +15,14 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Server.Clothing.Components { [RegisterComponent] [ComponentReference(typeof(IActivate))] - public sealed class MagbootsComponent : SharedMagbootsComponent, IUnequipped, IEquipped, IUse, IActivate + public sealed class MagbootsComponent : SharedMagbootsComponent, IUse, IActivate { - [ComponentDependency] private ItemComponent? _item = null; + [ComponentDependency] private SharedItemComponent? _item = null; [ComponentDependency] private ItemActionsComponent? _itemActions = null; [ComponentDependency] private SpriteComponent? _sprite = null; @@ -40,7 +38,12 @@ namespace Content.Server.Clothing.Components { _on = value; - UpdateContainer(); + if (Owner.TryGetContainer(out var container) && EntitySystem.Get() + .TryGetSlotEntity(container.Owner, "shoes", out var entityUid) && entityUid == Owner) + { + EntitySystem.Get().UpdateMagbootEffects(container.Owner, Owner, true, this); + } + _itemActions?.Toggle(ItemActionType.ToggleMagboots, On); if (_item != null) _item.EquippedPrefix = On ? "on" : null; @@ -55,54 +58,6 @@ namespace Content.Server.Clothing.Components On = !On; } - void IUnequipped.Unequipped(UnequippedEventArgs eventArgs) - { - if (On && eventArgs.Slot == Slots.SHOES) - { - if (_entMan.TryGetComponent(eventArgs.User, out MovedByPressureComponent? movedByPressure)) - { - movedByPressure.Enabled = true; - } - - if (_entMan.TryGetComponent(eventArgs.User, out ServerAlertsComponent? alerts)) - { - alerts.ClearAlert(AlertType.Magboots); - } - } - } - - void IEquipped.Equipped(EquippedEventArgs eventArgs) - { - UpdateContainer(); - } - - private void UpdateContainer() - { - if (!Owner.TryGetContainer(out var container)) - return; - - if (_entMan.TryGetComponent(container.Owner, out InventoryComponent? inventoryComponent) - && inventoryComponent.GetSlotItem(Slots.SHOES)?.Owner == Owner) - { - if (_entMan.TryGetComponent(container.Owner, out MovedByPressureComponent? movedByPressure)) - { - movedByPressure.Enabled = false; - } - - if (_entMan.TryGetComponent(container.Owner, out ServerAlertsComponent? alerts)) - { - if (On) - { - alerts.ShowAlert(AlertType.Magboots); - } - else - { - alerts.ClearAlert(AlertType.Magboots); - } - } - } - } - bool IUse.UseEntity(UseEntityEventArgs eventArgs) { Toggle(eventArgs.User); diff --git a/Content.Server/Clothing/MagbootsSystem.cs b/Content.Server/Clothing/MagbootsSystem.cs index 89d1fedcab..c2ce0a1770 100644 --- a/Content.Server/Clothing/MagbootsSystem.cs +++ b/Content.Server/Clothing/MagbootsSystem.cs @@ -1,4 +1,8 @@ +using Content.Server.Alert; +using Content.Server.Atmos.Components; using Content.Server.Clothing.Components; +using Content.Shared.Alert; +using Content.Shared.Inventory.Events; using Content.Shared.Movement.EntitySystems; using Content.Shared.Slippery; using Content.Shared.Verbs; @@ -16,6 +20,48 @@ namespace Content.Server.Clothing SubscribeLocalEvent(AddToggleVerb); SubscribeLocalEvent(OnSlipAttempt); SubscribeLocalEvent(OnRefreshMovespeed); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); + } + + public void UpdateMagbootEffects(EntityUid parent, EntityUid uid, bool state, MagbootsComponent? component) + { + if (!Resolve(uid, ref component)) + return; + state = state && component.On; + + if (TryComp(parent, out MovedByPressureComponent? movedByPressure)) + { + movedByPressure.Enabled = state; + } + + if (TryComp(parent, out ServerAlertsComponent? alerts)) + { + if (state) + { + alerts.ShowAlert(AlertType.Magboots); + } + else + { + alerts.ClearAlert(AlertType.Magboots); + } + } + } + + private void OnGotUnequipped(EntityUid uid, MagbootsComponent component, GotUnequippedEvent args) + { + if (args.Slot == "shoes") + { + UpdateMagbootEffects(args.Equipee, uid, true, component); + } + } + + private void OnGotEquipped(EntityUid uid, MagbootsComponent component, GotEquippedEvent args) + { + if (args.Slot == "shoes") + { + UpdateMagbootEffects(args.Equipee, uid, false, component); + } } private void OnRefreshMovespeed(EntityUid uid, MagbootsComponent component, RefreshMovementSpeedModifiersEvent args) diff --git a/Content.Server/Construction/ConstructionSystem.Initial.cs b/Content.Server/Construction/ConstructionSystem.Initial.cs index 5de9d4f8a5..8f7e24d4be 100644 --- a/Content.Server/Construction/ConstructionSystem.Initial.cs +++ b/Content.Server/Construction/ConstructionSystem.Initial.cs @@ -5,8 +5,6 @@ using System.Threading.Tasks; using Content.Server.Construction.Components; using Content.Server.DoAfter; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Storage.Components; using Content.Shared.ActionBlocker; using Content.Shared.Construction; @@ -14,6 +12,8 @@ using Content.Shared.Construction.Prototypes; using Content.Shared.Construction.Steps; using Content.Shared.Coordinates; using Content.Shared.Interaction.Helpers; +using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.Popups; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -28,6 +28,8 @@ namespace Content.Server.Construction public partial class ConstructionSystem { + [Dependency] private readonly InventorySystem _inventorySystem = default!; + // --- WARNING! LEGACY CODE AHEAD! --- // This entire file contains the legacy code for initial construction. // This is bound to be replaced by a better alternative (probably using dummy entities) @@ -61,11 +63,12 @@ namespace Content.Server.Construction } } - if (EntityManager.TryGetComponent(user!, out InventoryComponent? inventory)) + if (_inventorySystem.TryGetContainerSlotEnumerator(user, out var containerSlotEnumerator)) { - foreach (var held in inventory.GetAllHeldItems()) + while (containerSlotEnumerator.MoveNext(out var containerSlot)) { - if (EntityManager.TryGetComponent(held, out ServerStorageComponent? storage)) + if(!containerSlot.ContainedEntity.HasValue) continue; + if (EntityManager.TryGetComponent(containerSlot.ContainedEntity.Value, out ServerStorageComponent? storage)) { foreach (var storedEntity in storage.StoredEntities!) { @@ -73,7 +76,7 @@ namespace Content.Server.Construction } } - yield return held; + yield return containerSlot.ContainedEntity.Value; } } @@ -330,7 +333,7 @@ namespace Content.Server.Construction } if (await Construct(user, "item_construction", constructionGraph, edge, targetNode) is {Valid: true} item && - EntityManager.TryGetComponent(item, out ItemComponent? itemComp)) + EntityManager.TryGetComponent(item, out SharedItemComponent? itemComp)) hands.PutInHandOrDrop(itemComp); } diff --git a/Content.Server/Conveyor/ConveyorComponent.cs b/Content.Server/Conveyor/ConveyorComponent.cs index 909a91d6fb..83cc2cb1ca 100644 --- a/Content.Server/Conveyor/ConveyorComponent.cs +++ b/Content.Server/Conveyor/ConveyorComponent.cs @@ -1,15 +1,7 @@ -using System.Collections.Generic; -using Content.Server.Items; -using Content.Server.MachineLinking.Components; -using Content.Server.Power.Components; using Content.Shared.Conveyor; -using Content.Shared.MachineLinking; -using Robust.Server.GameObjects; using Robust.Shared.Analyzers; -using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.Maths; -using Robust.Shared.Physics; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; diff --git a/Content.Server/Conveyor/ConveyorSystem.cs b/Content.Server/Conveyor/ConveyorSystem.cs index 91668d58c9..6216ccfc0a 100644 --- a/Content.Server/Conveyor/ConveyorSystem.cs +++ b/Content.Server/Conveyor/ConveyorSystem.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; -using Content.Server.Items; using Content.Server.MachineLinking.Events; using Content.Server.MachineLinking.Models; using Content.Server.Power.Components; using Content.Server.Stunnable; using Content.Shared.Conveyor; +using Content.Shared.Item; using Content.Shared.MachineLinking; using Content.Shared.Movement.Components; using Content.Shared.Popups; @@ -104,7 +104,7 @@ namespace Content.Server.Conveyor return false; } - if (EntityManager.HasComponent(component.Owner)) + if (EntityManager.HasComponent(component.Owner)) { return false; } diff --git a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs index aab960bba6..0977a293f3 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using Content.Server.Atmos; using Content.Server.Disposal.Tube.Components; -using Content.Server.Items; using Content.Shared.Atmos; using Content.Shared.Body.Components; +using Content.Shared.Item; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -81,7 +81,7 @@ namespace Content.Server.Disposal.Unit.Components return false; } - return _entMan.HasComponent(entity) || + return _entMan.HasComponent(entity) || _entMan.HasComponent(entity); } diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index 65d13c5495..a8a47cccb1 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -8,13 +8,13 @@ using Content.Server.Disposal.Tube.Components; using Content.Server.Disposal.Unit.Components; using Content.Server.DoAfter; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Power.Components; using Content.Shared.ActionBlocker; using Content.Shared.Atmos; using Content.Shared.Disposal; using Content.Shared.Disposal.Components; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Movement; using Content.Shared.Popups; using Content.Shared.Throwing; @@ -369,7 +369,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems { // TODO: We need to use a specific collision method (which sloth hasn't coded yet) for actual bounds overlaps. // Check for itemcomp as we won't just block the disposal unit "sleeping" for something it can't collide with anyway. - if (!EntityManager.HasComponent(uid) && body.GetWorldAABB().Intersects(disposalsBounds!.Value)) continue; + if (!EntityManager.HasComponent(uid) && body.GetWorldAABB().Intersects(disposalsBounds!.Value)) continue; component.RecentlyEjected.RemoveAt(i); } } diff --git a/Content.Server/DoAfter/DoAfter.cs b/Content.Server/DoAfter/DoAfter.cs index 4e7ef466d6..5c847e41b0 100644 --- a/Content.Server/DoAfter/DoAfter.cs +++ b/Content.Server/DoAfter/DoAfter.cs @@ -1,8 +1,7 @@ using System; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Items; -using Content.Server.Stunnable.Components; +using Content.Shared.Item; using Content.Shared.Stunnable; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -33,7 +32,7 @@ namespace Content.Server.DoAfter // NeedHand private readonly string? _activeHand; - private readonly ItemComponent? _activeItem; + private readonly SharedItemComponent? _activeItem; public DoAfter(DoAfterEventArgs eventArgs, IEntityManager entityManager) { diff --git a/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs b/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs index 28684dc9ca..65d130dd04 100644 --- a/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs +++ b/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs @@ -1,12 +1,11 @@ using Content.Server.DoAfter; using Content.Server.Engineering.Components; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Shared.Interaction; using Content.Shared.Interaction.Helpers; +using Content.Shared.Item; using JetBrains.Annotations; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; namespace Content.Server.Engineering.EntitySystems { @@ -47,7 +46,7 @@ namespace Content.Server.Engineering.EntitySystems var entity = EntityManager.SpawnEntity(component.Prototype, EntityManager.GetComponent(component.Owner).Coordinates); if (EntityManager.TryGetComponent(args.User, out var hands) - && EntityManager.TryGetComponent(entity, out var item)) + && EntityManager.TryGetComponent(entity, out var item)) { hands.PutInHandOrDrop(item); } diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index 91750ea0c4..1737003091 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using Content.Server.Flash.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Stunnable; using Content.Server.Weapon.Melee; using Content.Shared.Examine; @@ -20,6 +18,7 @@ using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Player; using Robust.Shared.Timing; +using InventoryComponent = Content.Shared.Inventory.InventoryComponent; namespace Content.Server.Flash { @@ -28,6 +27,7 @@ namespace Content.Server.Flash [Dependency] private readonly IEntityLookup _entityLookup = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly StunSystem _stunSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; public override void Initialize() { @@ -187,8 +187,8 @@ namespace Content.Server.Flash private void OnInventoryFlashAttempt(EntityUid uid, InventoryComponent component, FlashAttemptEvent args) { // Forward the event to the glasses, if any. - if(component.TryGetSlotItem(EquipmentSlotDefines.Slots.EYES, out ItemComponent? glasses)) - RaiseLocalEvent(glasses.Owner, args); + if(_inventorySystem.TryGetSlotEntity(uid, "eyes", out var slotEntity, component)) + RaiseLocalEvent(slotEntity.Value, args); } private void OnFlashImmunityFlashAttempt(EntityUid uid, FlashImmunityComponent component, FlashAttemptEvent args) diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index bb1662cebc..cdadded588 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -6,17 +6,12 @@ using Content.Server.Access.Systems; using Content.Server.Ghost; using Content.Server.Ghost.Components; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; -using Content.Server.PDA; using Content.Server.Players; using Content.Server.Roles; using Content.Server.Spawners.Components; using Content.Server.Speech.Components; using Content.Server.Station; using Content.Shared.Access.Components; -using Content.Shared.Administration.Logs; -using Content.Shared.CharacterAppearance.Systems; using Content.Shared.Database; using Content.Shared.GameTicking; using Content.Shared.Ghost; @@ -33,7 +28,6 @@ using Robust.Shared.Map; using Robust.Shared.Random; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; -using static Content.Server.Station.StationSystem; namespace Content.Server.GameTicking { @@ -43,6 +37,7 @@ namespace Content.Server.GameTicking private const string ObserverPrototypeName = "MobObserver"; [Dependency] private readonly IdCardSystem _cardSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; /// /// Can't yet be removed because every test ever seems to depend on it. I'll make removing this a different PR. @@ -244,15 +239,15 @@ namespace Content.Server.GameTicking #region Equip Helpers public void EquipStartingGear(EntityUid entity, StartingGearPrototype startingGear, HumanoidCharacterProfile? profile) { - if (EntityManager.TryGetComponent(entity, out InventoryComponent? inventory)) + if (_inventorySystem.TryGetSlots(entity, out var slotDefinitions)) { - foreach (var slot in EquipmentSlotDefines.AllSlots) + foreach (var slot in slotDefinitions) { - var equipmentStr = startingGear.GetGear(slot, profile); + var equipmentStr = startingGear.GetGear(slot.Name, profile); if (!string.IsNullOrEmpty(equipmentStr)) { var equipmentEntity = EntityManager.SpawnEntity(equipmentStr, EntityManager.GetComponent(entity).Coordinates); - inventory.Equip(slot, EntityManager.GetComponent(equipmentEntity)); + _inventorySystem.TryEquip(entity, equipmentEntity, slot.Name, true); } } } @@ -270,17 +265,10 @@ namespace Content.Server.GameTicking public void EquipIdCard(EntityUid entity, string characterName, JobPrototype jobPrototype) { - if (!EntityManager.TryGetComponent(entity, out InventoryComponent? inventory)) + if (!_inventorySystem.TryGetSlotEntity(entity, "id", out var idUid)) return; - if (!inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item)) - { - return; - } - - var itemEntity = item.Owner; - - if (!EntityManager.TryGetComponent(itemEntity, out PDAComponent? pdaComponent) || pdaComponent.ContainedID == null) + if (!EntityManager.TryGetComponent(idUid, out PDAComponent? pdaComponent) || pdaComponent.ContainedID == null) return; var card = pdaComponent.ContainedID; diff --git a/Content.Server/GameTicking/Rules/TraitorDeathMatchRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorDeathMatchRuleSystem.cs index 388c4a0c76..146c7e49bb 100644 --- a/Content.Server/GameTicking/Rules/TraitorDeathMatchRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorDeathMatchRuleSystem.cs @@ -4,8 +4,6 @@ using System.Linq; using Content.Server.Atmos.EntitySystems; using Content.Server.Chat.Managers; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.PDA; using Content.Server.Players; using Content.Server.Spawners.Components; @@ -42,6 +40,7 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly MaxTimeRestartRuleSystem _restarter = default!; + [Dependency] private readonly InventorySystem _inventory = default!; public override string Prototype => "TraitorDeathMatch"; @@ -86,13 +85,13 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem // Delete anything that may contain "dangerous" role-specific items. // (This includes the PDA, as everybody gets the captain PDA in this mode for true-all-access reasons.) - if (mind.OwnedEntity is {Valid: true} owned && TryComp(owned, out InventoryComponent? inventory)) + if (mind.OwnedEntity is {Valid: true} owned) { - var victimSlots = new[] {EquipmentSlotDefines.Slots.IDCARD, EquipmentSlotDefines.Slots.BELT, EquipmentSlotDefines.Slots.BACKPACK}; + var victimSlots = new[] {"id", "belt", "back"}; foreach (var slot in victimSlots) { - if (inventory.TryGetSlotItem(slot, out ItemComponent? vItem)) - Del(vItem.Owner); + if(_inventory.TryUnequip(owned, slot, out var entityUid, true, true)) + Del(entityUid.Value); } // Replace their items: @@ -101,15 +100,15 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem // pda var newPDA = Spawn(PDAPrototypeName, ownedCoords); - inventory.Equip(EquipmentSlotDefines.Slots.IDCARD, Comp(newPDA)); + _inventory.TryEquip(owned, newPDA, "id", true); // belt var newTmp = Spawn(BeltPrototypeName, ownedCoords); - inventory.Equip(EquipmentSlotDefines.Slots.BELT, Comp(newTmp)); + _inventory.TryEquip(owned, newTmp, "belt", true); // backpack newTmp = Spawn(BackpackPrototypeName, ownedCoords); - inventory.Equip(EquipmentSlotDefines.Slots.BACKPACK, Comp(newTmp)); + _inventory.TryEquip(owned, newTmp, "back", true); // Like normal traitors, they need access to a traitor account. var uplinkAccount = new UplinkAccount(startingBalance, owned); diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs index 67bae906e4..0e5e57747d 100644 --- a/Content.Server/Guardian/GuardianSystem.cs +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Actions; using Content.Server.DoAfter; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; using Content.Server.Popups; using Content.Shared.Actions; using Content.Shared.Actions.Components; @@ -10,7 +9,6 @@ using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.MobState; -using Content.Shared.MobState.EntitySystems; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Containers; diff --git a/Content.Server/Hands/Components/HandsComponent.cs b/Content.Server/Hands/Components/HandsComponent.cs index a3c973b8de..932d634223 100644 --- a/Content.Server/Hands/Components/HandsComponent.cs +++ b/Content.Server/Hands/Components/HandsComponent.cs @@ -4,12 +4,12 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Act; using Content.Server.Interaction; -using Content.Server.Items; using Content.Server.Popups; using Content.Server.Pulling; using Content.Shared.Audio; using Content.Shared.Body.Part; using Content.Shared.Hands.Components; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Pulling.Components; using Content.Shared.Sound; @@ -39,7 +39,7 @@ namespace Content.Server.Hands.Components protected override void OnHeldEntityRemovedFromHand(EntityUid heldEntity, HandState handState) { - if (_entities.TryGetComponent(heldEntity, out ItemComponent? item)) + if (_entities.TryGetComponent(heldEntity, out SharedItemComponent? item)) { item.RemovedFromSlot(); _entitySystemManager.GetEntitySystem().UnequippedHandInteraction(Owner, heldEntity, handState); @@ -153,19 +153,19 @@ namespace Content.Server.Hands.Components /// /// Tries to get the ItemComponent on the entity held by a hand. /// - public ItemComponent? GetItem(string handName) + public SharedItemComponent? GetItem(string handName) { if (!TryGetHeldEntity(handName, out var heldEntity)) return null; - _entities.TryGetComponent(heldEntity, out ItemComponent? item); + _entities.TryGetComponent(heldEntity, out SharedItemComponent? item); return item; } /// /// Tries to get the ItemComponent on the entity held by a hand. /// - public bool TryGetItem(string handName, [NotNullWhen(true)] out ItemComponent? item) + public bool TryGetItem(string handName, [NotNullWhen(true)] out SharedItemComponent? item) { item = null; @@ -178,23 +178,23 @@ namespace Content.Server.Hands.Components /// /// Tries to get the ItemComponent off the entity in the active hand. /// - public ItemComponent? GetActiveHand + public SharedItemComponent? GetActiveHand { get { if (!TryGetActiveHeldEntity(out var heldEntity)) return null; - _entities.TryGetComponent(heldEntity, out ItemComponent? item); + _entities.TryGetComponent(heldEntity, out SharedItemComponent? item); return item; } } - public IEnumerable GetAllHeldItems() + public IEnumerable GetAllHeldItems() { foreach (var entity in GetAllHeldEntities()) { - if (_entities.TryGetComponent(entity, out ItemComponent? item)) + if (_entities.TryGetComponent(entity, out SharedItemComponent? item)) yield return item; } } @@ -202,7 +202,7 @@ namespace Content.Server.Hands.Components /// /// Checks if any hand can pick up an item. /// - public bool CanPutInHand(ItemComponent item, bool mobCheck = true) + public bool CanPutInHand(SharedItemComponent item, bool mobCheck = true) { var entity = item.Owner; diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index 8b216ed1b4..b1a6d164d5 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -3,8 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Hands.Components; using Content.Server.Interaction; -using Content.Server.Inventory.Components; -using Content.Server.Items; +using Content.Server.Inventory; using Content.Server.Stack; using Content.Server.Storage.Components; using Content.Server.Throwing; @@ -13,6 +12,7 @@ using Content.Shared.Examine; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Input; +using Content.Shared.Inventory; using Content.Shared.Physics.Pull; using Content.Shared.Popups; using JetBrains.Annotations; @@ -26,14 +26,13 @@ using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Players; using Robust.Shared.Utility; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Server.Hands.Systems { [UsedImplicitly] internal sealed class HandsSystem : SharedHandsSystem { - [Dependency] private readonly InteractionSystem _interactionSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!; [Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; @@ -261,15 +260,15 @@ namespace Content.Server.Hands.Systems private void HandleSmartEquipBackpack(ICommonSession? session) { - HandleSmartEquip(session, Slots.BACKPACK); + HandleSmartEquip(session, "back"); } private void HandleSmartEquipBelt(ICommonSession? session) { - HandleSmartEquip(session, Slots.BELT); + HandleSmartEquip(session, "belt"); } - private void HandleSmartEquip(ICommonSession? session, Slots equipmentSlot) + private void HandleSmartEquip(ICommonSession? session, string equipmentSlot) { if (session is not IPlayerSession playerSession) return; @@ -277,14 +276,13 @@ namespace Content.Server.Hands.Systems if (playerSession.AttachedEntity is not {Valid: true} plyEnt || !EntityManager.EntityExists(plyEnt)) return; - if (!EntityManager.TryGetComponent(plyEnt, out SharedHandsComponent? hands) || - !EntityManager.TryGetComponent(plyEnt, out InventoryComponent? inventory)) + if (!EntityManager.TryGetComponent(plyEnt, out SharedHandsComponent? hands)) return; - if (!inventory.TryGetSlotItem(equipmentSlot, out ItemComponent? equipmentItem) || - !EntityManager.TryGetComponent(equipmentItem.Owner, out ServerStorageComponent? storageComponent)) + if (!_inventorySystem.TryGetSlotEntity(plyEnt, equipmentSlot, out var slotEntity) || + !EntityManager.TryGetComponent(slotEntity, out ServerStorageComponent? storageComponent)) { - plyEnt.PopupMessage(Loc.GetString("hands-system-missing-equipment-slot", ("slotName", SlotNames[equipmentSlot].ToLower()))); + plyEnt.PopupMessage(Loc.GetString("hands-system-missing-equipment-slot", ("slotName", equipmentSlot))); return; } @@ -296,7 +294,7 @@ namespace Content.Server.Hands.Systems { if (storageComponent.StoredEntities.Count == 0) { - plyEnt.PopupMessage(Loc.GetString("hands-system-empty-equipment-slot", ("slotName", SlotNames[equipmentSlot].ToLower()))); + plyEnt.PopupMessage(Loc.GetString("hands-system-empty-equipment-slot", ("slotName", equipmentSlot))); } else { diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index 7aef3681c7..5ffee37741 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -5,16 +5,15 @@ using System.Threading.Tasks; using Content.Server.Administration.Logs; using Content.Server.CombatMode; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Pulling; using Content.Server.Storage.Components; using Content.Shared.ActionBlocker; -using Content.Shared.Administration.Logs; using Content.Shared.Database; using Content.Shared.DragDrop; using Content.Shared.Input; using Content.Shared.Interaction; using Content.Shared.Interaction.Helpers; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Pulling.Components; using Content.Shared.Weapons.Melee; @@ -358,7 +357,7 @@ namespace Content.Server.Interaction } } } - else if (!wideAttack && target != null && HasComp(target.Value)) + else if (!wideAttack && target != null && HasComp(target.Value)) { // We pick up items if our hand is empty, even if we're in combat mode. InteractHand(user, target.Value); diff --git a/Content.Server/Inventory/Components/DebugEquipComponent.cs b/Content.Server/Inventory/Components/DebugEquipComponent.cs deleted file mode 100644 index 9f648aa886..0000000000 --- a/Content.Server/Inventory/Components/DebugEquipComponent.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Content.Shared.Hands; -using Content.Shared.Inventory; -using Content.Shared.Popups; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; - -namespace Content.Server.Inventory.Components -{ - /// - /// Pops up a message when equipped / unequipped (including hands). - /// For debugging purposes. - /// - [RegisterComponent] - public class DebugEquipComponent : Component, IEquipped, IEquippedHand, IUnequipped, IUnequippedHand - { - [Dependency] private readonly IEntityManager _entMan = default!; - - public override string Name => "DebugEquip"; - - void IEquipped.Equipped(EquippedEventArgs eventArgs) - { - eventArgs.User.PopupMessage("equipped " + _entMan.GetComponent(Owner).EntityName); - } - - void IEquippedHand.EquippedHand(EquippedHandEventArgs eventArgs) - { - eventArgs.User.PopupMessage("equipped hand " + _entMan.GetComponent(Owner).EntityName); - } - - void IUnequipped.Unequipped(UnequippedEventArgs eventArgs) - { - eventArgs.User.PopupMessage("unequipped " + _entMan.GetComponent(Owner).EntityName); - } - - void IUnequippedHand.UnequippedHand(UnequippedHandEventArgs eventArgs) - { - eventArgs.User.PopupMessage("unequipped hand" + _entMan.GetComponent(Owner).EntityName); - } - } -} diff --git a/Content.Server/Inventory/Components/HumanInventoryControllerComponent.cs b/Content.Server/Inventory/Components/HumanInventoryControllerComponent.cs deleted file mode 100644 index 6fc56584b2..0000000000 --- a/Content.Server/Inventory/Components/HumanInventoryControllerComponent.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Server.Items; -using Content.Shared.Item; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using static Content.Shared.Inventory.EquipmentSlotDefines; - -namespace Content.Server.Inventory.Components -{ - // 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 = default!; - - protected override void Initialize() - { - base.Initialize(); - - _inventory = Owner.EnsureComponent(); - } - - bool IInventoryController.CanEquip(Slots slot, EntityUid entity, bool flagsCheck, [NotNullWhen(false)] out string? reason) - { - var slotMask = SlotMasks[slot]; - reason = null; - - 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) - { - reason = Loc.GetString(slotMask == SlotFlags.IDCARD - ? "human-inventory-controller-component-need-uniform-to-store-in-id-slot-text" - : "human-inventory-controller-component-need-uniform-to-store-in-pockets-text"); - return false; - } - - if (slotMask == SlotFlags.POCKET) - { - var itemComponent = IoCManager.Resolve().GetComponent(entity); - - // If this item is small enough then it always fits in pockets. - if (itemComponent.Size <= (int) ReferenceSizes.Pocket) - { - return true; - } - else if (!flagsCheck) - { - reason = Loc.GetString("human-inventory-controller-component-too-large-text"); - } - } - } - - // Standard flag check. - return flagsCheck; - } - - public void CheckUniformExists() { Owner.SpawnTimer(0, DropIdAndPocketsIfWeNoLongerHaveAUniform); } - - // Hey, it's descriptive. - private void DropIdAndPocketsIfWeNoLongerHaveAUniform() - { - if (Deleted) - { - return; - } - - 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); - } - } -} diff --git a/Content.Server/Inventory/Components/IInventoryController.cs b/Content.Server/Inventory/Components/IInventoryController.cs deleted file mode 100644 index b55db7da67..0000000000 --- a/Content.Server/Inventory/Components/IInventoryController.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Robust.Shared.GameObjects; -using static Content.Shared.Inventory.EquipmentSlotDefines; - -namespace Content.Server.Inventory.Components -{ - /// - /// Allows for overriding inventory-related behavior on an entity. - /// - public interface IInventoryController - { - /// - /// Can be implemented to override "can this item be equipped" behavior. - /// - /// The slot to be equipped into. - /// The entity to equip. - /// Whether the entity passes default slot masks & flags checks. - /// The translated reason why the item cannot be equiped, if this function returns false. Can be null. - /// True if the entity can be equipped, false otherwise - bool CanEquip(Slots slot, EntityUid entity, bool flagsCheck, [NotNullWhen(false)] out string? reason) - { - reason = null; - return flagsCheck; - } - - bool CanEquip(Slots slot, EntityUid entity, bool flagsCheck) => CanEquip(slot, entity, flagsCheck, out _); - } -} diff --git a/Content.Server/Inventory/Components/InventoryComponent.cs b/Content.Server/Inventory/Components/InventoryComponent.cs deleted file mode 100644 index 47fa7c7958..0000000000 --- a/Content.Server/Inventory/Components/InventoryComponent.cs +++ /dev/null @@ -1,576 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Content.Server.Clothing.Components; -using Content.Server.Hands.Components; -using Content.Server.Interaction; -using Content.Server.Items; -using Content.Server.Storage.Components; -using Content.Shared.ActionBlocker; -using Content.Shared.Acts; -using Content.Shared.Inventory; -using Content.Shared.Movement.EntitySystems; -using Content.Shared.Popups; -using Robust.Shared.Audio; -using Robust.Shared.Containers; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using Robust.Shared.Map; -using Robust.Shared.Network; -using Robust.Shared.Player; -using Robust.Shared.Players; -using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; -using static Content.Shared.Inventory.SharedInventoryComponent.ClientInventoryMessage; - -namespace Content.Server.Inventory.Components -{ - [RegisterComponent] - [ComponentReference(typeof(SharedInventoryComponent))] - public class InventoryComponent : SharedInventoryComponent, IExAct - { - [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; - [Dependency] private readonly IEntityManager _entities = default!; - - [ViewVariables] private readonly Dictionary _slotContainers = new(); - - private KeyValuePair? _hoverEntity; - - public IEnumerable Slots => _slotContainers.Keys; - - public event Action? OnItemChanged; - - protected override void Initialize() - { - base.Initialize(); - - foreach (var slotName in InventoryInstance.SlotMasks) - { - if (slotName != EquipmentSlotDefines.Slots.NONE) - { - AddSlot(slotName); - } - } - } - - protected override void OnRemove() - { - var slots = _slotContainers.Keys.ToList(); - - foreach (var slot in slots) - { - if (TryGetSlotItem(slot, out ItemComponent? item)) - { - _entities.DeleteEntity(item.Owner); - } - - RemoveSlot(slot); - } - - base.OnRemove(); - } - - public IEnumerable GetAllHeldItems() - { - foreach (var (_, container) in _slotContainers) - { - foreach (var entity in container.ContainedEntities) - { - yield return entity; - } - } - } - - /// - /// Helper to get container name for specified slot on this component - /// - /// - /// - private string GetSlotString(Slots slot) - { - return Name + "_" + Enum.GetName(typeof(Slots), slot); - } - - /// - /// Gets the clothing equipped to the specified slot. - /// - /// The slot to get the item for. - /// Null if the slot is empty, otherwise the item. - public ItemComponent? GetSlotItem(Slots slot) - { - return GetSlotItem(slot); - } - - public IEnumerable LookupItems() where T : Component - { - return _slotContainers.Values - .SelectMany(x => x.ContainedEntities.Select(e => _entities.GetComponentOrNull(e))) - .Where(x => x != null); - } - - public T? GetSlotItem(Slots slot) where T : ItemComponent - { - if (!_slotContainers.ContainsKey(slot)) - { - return null; - } - - var containedEntity = _slotContainers[slot].ContainedEntity; - if (containedEntity != null && _entities.GetComponent(containedEntity.Value).EntityDeleted) - { - _slotContainers.Remove(slot); - containedEntity = null; - Dirty(); - } - - return containedEntity.HasValue ? _entities.GetComponent(containedEntity.Value) : null; - } - - public bool TryGetSlotItem(Slots slot, [NotNullWhen(true)] out T? itemComponent) where T : ItemComponent - { - itemComponent = GetSlotItem(slot); - return itemComponent != null; - } - - /// - /// Equips slothing to the specified slot. - /// - /// - /// This will fail if there is already an item in the specified slot. - /// - /// The slot to put the item in. - /// The item to insert into the slot. - /// Whether to perform an ActionBlocker check to the entity. - /// The translated reason why the item cannot be equipped, if this function returns false. Can be null. - /// True if the item was successfully inserted, false otherwise. - public bool Equip(Slots slot, ItemComponent item, bool mobCheck, [NotNullWhen(false)] out string? reason) - { - if (item == null) - { - throw new ArgumentNullException(nameof(item), - "Clothing must be passed here. To remove some clothing from a slot, use Unequip()"); - } - - if (!CanEquip(slot, item, mobCheck, out reason)) - { - return false; - } - - var inventorySlot = _slotContainers[slot]; - if (!inventorySlot.Insert(item.Owner)) - { - reason = Loc.GetString("inventory-component-on-equip-cannot"); - return false; - } - - // TODO: Make clothing component not inherit ItemComponent, for fuck's sake. - // TODO: Make clothing component not required for playing a sound on equip... Move it to its own component. - if (mobCheck && item is ClothingComponent { EquipSound: {} equipSound }) - { - SoundSystem.Play(Filter.Pvs(Owner), equipSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f)); - } - - _entitySystemManager.GetEntitySystem().EquippedInteraction(Owner, item.Owner, slot); - - OnItemChanged?.Invoke(); - - Dirty(); - - UpdateMovementSpeed(); - - return true; - } - - public bool Equip(Slots slot, ItemComponent item, bool mobCheck = true) => - Equip(slot, item, mobCheck, out var _); - - public bool Equip(Slots slot, EntityUid entity, bool mobCheck = true) => - Equip(slot, _entities.GetComponent(entity), mobCheck); - - /// - /// Checks whether an item can be put in the specified slot. - /// - /// The slot to check for. - /// The item to check for. - /// The translated reason why the item cannot be equiped, if this function returns false. Can be null. - /// True if the item can be inserted into the specified slot. - public bool CanEquip(Slots slot, ItemComponent item, bool mobCheck, [NotNullWhen(false)] out string? reason) - { - var pass = false; - reason = null; - - if (mobCheck && !EntitySystem.Get().CanEquip(Owner)) - { - reason = Loc.GetString("inventory-component-can-equip-cannot"); - return false; - } - - if (item is ClothingComponent clothing) - { - if (clothing.SlotFlags != SlotFlags.PREVENTEQUIP && (clothing.SlotFlags & SlotMasks[slot]) != 0) - { - pass = true; - } - else - { - reason = Loc.GetString("inventory-component-can-equip-does-not-fit"); - } - } - - if (_entities.TryGetComponent(Owner, out IInventoryController? controller)) - { - pass = controller.CanEquip(slot, item.Owner, pass, out var controllerReason); - reason = controllerReason ?? reason; - } - - if (!pass) - { - reason = reason ?? Loc.GetString("inventory-component-can-equip-cannot"); - return false; - } - - var canEquip = pass && _slotContainers[slot].CanInsert(item.Owner); - - if (!canEquip) - { - reason = Loc.GetString("inventory-component-can-equip-cannot"); - } - - return canEquip; - } - - public bool CanEquip(Slots slot, ItemComponent item, bool mobCheck = true) => - CanEquip(slot, item, mobCheck, out var _); - - public bool CanEquip(Slots slot, EntityUid entity, bool mobCheck = true) => - CanEquip(slot, _entities.GetComponent(entity), mobCheck); - - /// - /// Drops the item in a slot. - /// - /// The slot to drop the item from. - /// True if an item was dropped, false otherwise. - /// Whether to perform an ActionBlocker check to the entity. - public bool Unequip(Slots slot, bool mobCheck = true) - { - if (!CanUnequip(slot, mobCheck)) - { - return false; - } - - var inventorySlot = _slotContainers[slot]; - - if (inventorySlot.ContainedEntity is not {Valid: true} entity) - { - return false; - } - - if (!inventorySlot.Remove(entity)) - { - return false; - } - - // TODO: The item should be dropped to the container our owner is in, if any. - _entities.GetComponent(entity).AttachParentToContainerOrGrid(); - - _entitySystemManager.GetEntitySystem().UnequippedInteraction(Owner, entity, slot); - - OnItemChanged?.Invoke(); - - Dirty(); - - UpdateMovementSpeed(); - - return true; - } - - private void UpdateMovementSpeed() - { - EntitySystem.Get().RefreshMovementSpeedModifiers(Owner); - } - - public void ForceUnequip(Slots slot) - { - var inventorySlot = _slotContainers[slot]; - if (inventorySlot.ContainedEntity is not {Valid: true} entity) - { - return; - } - - var item = _entities.GetComponent(entity); - inventorySlot.ForceRemove(entity); - - var itemTransform = _entities.GetComponent(entity); - - itemTransform.AttachParentToContainerOrGrid(); - - _entitySystemManager.GetEntitySystem().UnequippedInteraction(Owner, item.Owner, slot); - - OnItemChanged?.Invoke(); - - Dirty(); - } - - /// - /// Checks whether an item can be dropped from the specified slot. - /// - /// The slot to check for. - /// Whether to perform an ActionBlocker check to the entity. - /// - /// True if there is an item in the slot and it can be dropped, false otherwise. - /// - public bool CanUnequip(Slots slot, bool mobCheck = true) - { - if (mobCheck && !EntitySystem.Get().CanUnequip(Owner)) - return false; - - var inventorySlot = _slotContainers[slot]; - return inventorySlot.ContainedEntity != null && inventorySlot.CanRemove(inventorySlot.ContainedEntity.Value); - } - - /// - /// Adds a new slot to this inventory component. - /// - /// The name of the slot to add. - /// - /// Thrown if the slot with specified name already exists. - /// - public ContainerSlot AddSlot(Slots slot) - { - if (HasSlot(slot)) - { - throw new InvalidOperationException($"Slot '{slot}' already exists."); - } - - Dirty(); - - var container = ContainerHelpers.CreateContainer(Owner, GetSlotString(slot)); - container.OccludesLight = false; - _slotContainers[slot] = container; - - OnItemChanged?.Invoke(); - - return _slotContainers[slot]; - } - - /// - /// Removes a slot from this inventory component. - /// - /// - /// If the slot contains an item, the item is dropped. - /// - /// The name of the slot to remove. - public void RemoveSlot(Slots slot) - { - if (!HasSlot(slot)) - { - throw new InvalidOperationException($"Slot '{slot}' does not exist."); - } - - ForceUnequip(slot); - - var container = _slotContainers[slot]; - - container.Shutdown(); - _slotContainers.Remove(slot); - - OnItemChanged?.Invoke(); - - Dirty(); - } - - /// - /// Checks whether a slot with the specified name exists. - /// - /// The slot name to check. - /// True if the slot exists, false otherwise. - public bool HasSlot(Slots slot) - { - return _slotContainers.ContainsKey(slot); - } - - /// - /// The underlying Container System just notified us that an entity was removed from it. - /// We need to make sure we process that removed entity as being unequipped from the slot. - /// - public void ForceUnequip(IContainer container, EntityUid entity) - { - // make sure this is one of our containers. - // Technically the correct way would be to enumerate the possible slot names - // comparing with this container, but I might as well put the dictionary to good use. - if (container is not ContainerSlot slot || !_slotContainers.ContainsValue(slot)) - return; - - if (_entities.TryGetComponent(entity, out ItemComponent? itemComp)) - { - itemComp.RemovedFromSlot(); - } - - OnItemChanged?.Invoke(); - - Dirty(); - } - - /// - /// Message that tells us to equip or unequip items from the inventory slots - /// - /// - private async void HandleInventoryMessage(ClientInventoryMessage msg) - { - switch (msg.Updatetype) - { - case ClientInventoryUpdate.Equip: - { - var hands = _entities.GetComponent(Owner); - var activeHand = hands.ActiveHand; - var activeItem = hands.GetActiveHand; - if (activeHand != null && activeItem != null && _entities.TryGetComponent(activeItem.Owner, out ItemComponent? item)) - { - hands.TryDropNoInteraction(); - if (!Equip(msg.Inventoryslot, item, true, out var reason)) - { - hands.PutInHand(item); - Owner.PopupMessageCursor(reason); - } - } - - break; - } - case ClientInventoryUpdate.Use: - { - var interactionSystem = _entitySystemManager.GetEntitySystem(); - var hands = _entities.GetComponent(Owner); - var activeHand = hands.GetActiveHand; - var itemContainedInSlot = GetSlotItem(msg.Inventoryslot); - if (itemContainedInSlot != null) - { - if (activeHand != null) - { - await interactionSystem.InteractUsing(Owner, activeHand.Owner, itemContainedInSlot.Owner, - new EntityCoordinates()); - } - else if (Unequip(msg.Inventoryslot)) - { - hands.PutInHand(itemContainedInSlot); - } - } - - break; - } - case ClientInventoryUpdate.Hover: - { - var hands = _entities.GetComponent(Owner); - var activeHand = hands.GetActiveHand; - if (activeHand != null && GetSlotItem(msg.Inventoryslot) == null) - { - var canEquip = CanEquip(msg.Inventoryslot, activeHand, true, out var reason); - _hoverEntity = - new KeyValuePair(msg.Inventoryslot, - (Uid: activeHand.Owner, canEquip)); - - Dirty(); - } - - break; - } - } - } - - /// - [Obsolete("Component Messages are deprecated, use Entity Events instead.")] - public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, - ICommonSession? session = null) - { - base.HandleNetworkMessage(message, netChannel, session); - - if (session == null) - { - throw new ArgumentNullException(nameof(session)); - } - - switch (message) - { - case ClientInventoryMessage msg: - var playerentity = session.AttachedEntity; - - if (playerentity == Owner) - HandleInventoryMessage(msg); - break; - - case OpenSlotStorageUIMessage msg: - if (!HasSlot(msg.Slot)) // client input sanitization - return; - var item = GetSlotItem(msg.Slot); - if (item != null && _entities.TryGetComponent(item.Owner, out ServerStorageComponent? storage)) - storage.OpenStorageUI(Owner); - break; - } - } - - public override ComponentState GetComponentState() - { - var list = new List>(); - foreach (var (slot, container) in _slotContainers) - { - if (container is {ContainedEntity: { }}) - { - list.Add(new KeyValuePair(slot, container.ContainedEntity.Value)); - } - } - - var hover = _hoverEntity; - _hoverEntity = null; - - return new InventoryComponentState(list, hover); - } - - void IExAct.OnExplosion(ExplosionEventArgs eventArgs) - { - if (eventArgs.Severity < ExplosionSeverity.Heavy) - { - return; - } - - foreach (var slot in _slotContainers.Values.ToList()) - { - foreach (var entity in slot.ContainedEntities) - { - var exActs = _entities.GetComponents(entity).ToList(); - foreach (var exAct in exActs) - { - exAct.OnExplosion(eventArgs); - } - } - } - } - - public override bool IsEquipped(EntityUid item) - { - if (item == default) return false; - foreach (var containerSlot in _slotContainers.Values) - { - // we don't want a recursive check here - if (containerSlot.Contains(item)) - { - return true; - } - } - - return false; - } - - public override bool TryGetSlot(Slots slot, [NotNullWhen(true)] out EntityUid? item) - { - if (_slotContainers.TryGetValue(slot, out var container)) - { - item = container.ContainedEntity; - return item != null; - } - - item = null; - return false; - } - } -} diff --git a/Content.Server/Inventory/InventoryHelpers.cs b/Content.Server/Inventory/InventoryHelpers.cs deleted file mode 100644 index 821fdfdd51..0000000000 --- a/Content.Server/Inventory/InventoryHelpers.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Content.Server.Inventory.Components; -using Content.Server.Items; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Prototypes; -using static Content.Shared.Inventory.EquipmentSlotDefines; - -namespace Content.Server.Inventory -{ - public static class InventoryHelpers - { - public static bool SpawnItemInSlot(this InventoryComponent inventory, Slots slot, string prototype, bool mobCheck = false) - { - var entityManager = IoCManager.Resolve(); - var protoManager = IoCManager.Resolve(); - var user = inventory.Owner; - - // Let's do nothing if the owner of the inventory has been deleted. - if (entityManager.Deleted(user)) - return false; - - // If we don't have that slot or there's already an item there, we do nothing. - if (!inventory.HasSlot(slot) || inventory.TryGetSlotItem(slot, out ItemComponent? _)) - return false; - - // If the prototype in question doesn't exist, we do nothing. - if (!protoManager.HasIndex(prototype)) - return false; - - // Let's spawn this first... - var item = entityManager.SpawnEntity(prototype, entityManager.GetComponent(user).MapPosition); - - // Helper method that deletes the item and returns false. - bool DeleteItem() - { - entityManager.DeleteEntity(item); - return false; - } - - // If this doesn't have an item component, then we can't do anything with it. - if (!entityManager.TryGetComponent(item, out ItemComponent? itemComp)) - return DeleteItem(); - - // We finally try to equip the item, otherwise we delete it. - return inventory.Equip(slot, itemComp, mobCheck) || DeleteItem(); - } - } -} diff --git a/Content.Server/Inventory/InventorySystem.cs b/Content.Server/Inventory/InventorySystem.cs deleted file mode 100644 index 52344adcdd..0000000000 --- a/Content.Server/Inventory/InventorySystem.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Inventory.Components; -using Content.Server.Items; -using Content.Server.Temperature.Systems; -using Content.Shared.Inventory; -using Content.Shared.Slippery; -using Content.Shared.Damage; -using Content.Shared.Electrocution; -using Content.Shared.Movement.EntitySystems; -using Robust.Shared.Containers; -using Robust.Shared.GameObjects; - -namespace Content.Server.Inventory -{ - class InventorySystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(HandleRemovedFromContainer); - SubscribeLocalEvent(HandleInvRemovedFromContainer); - SubscribeLocalEvent(OnHighPressureEvent); - SubscribeLocalEvent(OnLowPressureEvent); - SubscribeLocalEvent(OnDamageModify); - SubscribeLocalEvent(OnElectrocutionAttempt); - SubscribeLocalEvent(OnSlipAttemptEvent); - SubscribeLocalEvent(OnRefreshMovespeed); - SubscribeLocalEvent(OnModifyTemperature); - } - - private void OnModifyTemperature(EntityUid uid, InventoryComponent component, ModifyChangedTemperatureEvent args) - { - RelayInventoryEvent(component, args); - } - - private void OnSlipAttemptEvent(EntityUid uid, InventoryComponent component, SlipAttemptEvent args) - { - if (component.TryGetSlotItem(EquipmentSlotDefines.Slots.SHOES, out ItemComponent? shoes)) - { - RaiseLocalEvent(shoes.Owner, args, false); - } - } - - private void OnRefreshMovespeed(EntityUid uid, InventoryComponent component, RefreshMovementSpeedModifiersEvent args) - { - RelayInventoryEvent(component, args); - } - - private static void HandleInvRemovedFromContainer(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args) - { - component.ForceUnequip(args.Container, args.Entity); - } - - private static void HandleRemovedFromContainer(EntityUid uid, HumanInventoryControllerComponent component, EntRemovedFromContainerMessage args) - { - component.CheckUniformExists(); - } - - private void OnHighPressureEvent(EntityUid uid, InventoryComponent component, HighPressureEvent args) - { - RelayInventoryEvent(component, args); - } - - private void OnLowPressureEvent(EntityUid uid, InventoryComponent component, LowPressureEvent args) - { - RelayInventoryEvent(component, args); - } - - private void OnElectrocutionAttempt(EntityUid uid, InventoryComponent component, ElectrocutionAttemptEvent args) - { - RelayInventoryEvent(component, args); - } - - private void OnDamageModify(EntityUid uid, InventoryComponent component, DamageModifyEvent args) - { - RelayInventoryEvent(component, args); - } - - private void RelayInventoryEvent(InventoryComponent component, T args) where T : EntityEventArgs - { - foreach (var equipped in component.GetAllHeldItems()) - { - RaiseLocalEvent(equipped, args, false); - } - } - } -} diff --git a/Content.Server/Inventory/ServerInventoryComponent.cs b/Content.Server/Inventory/ServerInventoryComponent.cs new file mode 100644 index 0000000000..25a68ab064 --- /dev/null +++ b/Content.Server/Inventory/ServerInventoryComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameObjects; + +namespace Content.Server.Inventory; + +[RegisterComponent] +[ComponentReference(typeof(InventoryComponent))] +public class ServerInventoryComponent : InventoryComponent { } diff --git a/Content.Server/Inventory/ServerInventorySystem.cs b/Content.Server/Inventory/ServerInventorySystem.cs new file mode 100644 index 0000000000..f9eed3a093 --- /dev/null +++ b/Content.Server/Inventory/ServerInventorySystem.cs @@ -0,0 +1,70 @@ +using Content.Server.Atmos; +using Content.Server.Hands.Components; +using Content.Server.Interaction; +using Content.Server.Storage.Components; +using Content.Server.Temperature.Systems; +using Content.Shared.Inventory; +using Content.Shared.Inventory.Events; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Map; +using InventoryComponent = Content.Shared.Inventory.InventoryComponent; + +namespace Content.Server.Inventory +{ + class ServerInventorySystem : InventorySystem + { + [Dependency] private readonly InteractionSystem _interactionSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); + + SubscribeNetworkEvent(OnNetworkEquip); + SubscribeNetworkEvent(OnNetworkUnequip); + SubscribeNetworkEvent(OnOpenSlotStorage); + SubscribeNetworkEvent(OnUseSlot); + } + + private void OnUseSlot(UseSlotNetworkMessage ev) + { + if (!TryComp(ev.Uid, out var hands) || !TryGetSlotEntity(ev.Uid, ev.Slot, out var itemUid)) + return; + + var activeHand = hands.GetActiveHand; + if (activeHand != null) + { + _interactionSystem.InteractUsing(ev.Uid, activeHand.Owner, itemUid.Value, + new EntityCoordinates()); + } + else if (TryUnequip(ev.Uid, ev.Slot)) + { + hands.PutInHand(itemUid.Value); + } + + } + + private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev) + { + if (TryGetSlotEntity(ev.Uid, ev.Slot, out var entityUid) && TryComp(entityUid, out var storageComponent)) + { + storageComponent.OpenStorageUI(ev.Uid); + } + } + + private void OnNetworkUnequip(TryUnequipNetworkMessage ev) + { + TryUnequip(ev.Actor, ev.Target, ev.Slot, ev.Silent, ev.Force); + } + + private void OnNetworkEquip(TryEquipNetworkMessage ev) + { + TryEquip(ev.Actor, ev.Target, ev.ItemUid, ev.Slot, ev.Silent, ev.Force); + } + } +} diff --git a/Content.Server/Items/ItemComponent.cs b/Content.Server/Items/ItemComponent.cs deleted file mode 100644 index d33ab54562..0000000000 --- a/Content.Server/Items/ItemComponent.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using Content.Shared.Item; -using Robust.Server.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; - -namespace Content.Server.Items -{ - [RegisterComponent] - [ComponentReference(typeof(SharedItemComponent))] - public class ItemComponent : SharedItemComponent - { - public override void RemovedFromSlot() - { - foreach (var component in IoCManager.Resolve().GetComponents(Owner)) - { - component.Visible = true; - } - } - - public override void EquippedToSlot() - { - foreach (var component in IoCManager.Resolve().GetComponents(Owner)) - { - component.Visible = false; - } - } - } -} - diff --git a/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs b/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs index 59dc087740..bfd8c9bf6b 100644 --- a/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs +++ b/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs @@ -1,6 +1,6 @@ using Content.Server.Hands.Components; using Content.Server.Holiday; -using Content.Server.Items; +using Content.Shared.Item; using Content.Shared.Roles; using JetBrains.Annotations; using Robust.Shared.GameObjects; @@ -33,7 +33,7 @@ namespace Content.Server.Jobs var entity = entMan.SpawnEntity(Prototype, entMan.GetComponent(mob).Coordinates); - if (!entMan.TryGetComponent(entity, out ItemComponent? item) || !entMan.TryGetComponent(mob, out HandsComponent? hands)) + if (!entMan.TryGetComponent(entity, out SharedItemComponent? item) || !entMan.TryGetComponent(mob, out HandsComponent? hands)) return; hands.PutInHand(item, false); diff --git a/Content.Server/Kitchen/Components/MicrowaveComponent.cs b/Content.Server/Kitchen/Components/MicrowaveComponent.cs index 714ce9c912..19858a4d28 100644 --- a/Content.Server/Kitchen/Components/MicrowaveComponent.cs +++ b/Content.Server/Kitchen/Components/MicrowaveComponent.cs @@ -6,7 +6,6 @@ using Content.Server.Chat.Managers; using Content.Server.Chemistry.Components; using Content.Server.Chemistry.EntitySystems; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.UserInterface; @@ -16,6 +15,7 @@ using Content.Shared.Body.Part; using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Kitchen; using Content.Shared.Kitchen.Components; using Content.Shared.Popups; @@ -284,7 +284,7 @@ namespace Content.Server.Kitchen.Components return true; } - if (!_entities.TryGetComponent(itemEntity, typeof(ItemComponent), out var food)) + if (!_entities.TryGetComponent(itemEntity, typeof(SharedItemComponent), out var food)) { Owner.PopupMessage(eventArgs.User, "microwave-component-interact-using-transfer-fail"); return false; diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs index 6062145c5f..1458e54736 100644 --- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs @@ -2,13 +2,13 @@ using System.Linq; using Content.Server.Chemistry.EntitySystems; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Kitchen.Components; using Content.Server.Kitchen.Events; using Content.Server.Power.Components; using Content.Server.Stack; using Content.Server.UserInterface; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Kitchen.Components; using Content.Shared.Popups; using Content.Shared.Random.Helpers; @@ -264,7 +264,7 @@ namespace Content.Server.Kitchen.EntitySystems if (user == null || !EntityManager.TryGetComponent(user.Value, out var hands) || - !EntityManager.TryGetComponent(beaker, out var item)) + !EntityManager.TryGetComponent(beaker, out var item)) return; hands.PutInHandOrDrop(item); diff --git a/Content.Server/Labels/Label/Components/HandLabelerComponent.cs b/Content.Server/Labels/Label/Components/HandLabelerComponent.cs index 396a538903..8849257fea 100644 --- a/Content.Server/Labels/Label/Components/HandLabelerComponent.cs +++ b/Content.Server/Labels/Label/Components/HandLabelerComponent.cs @@ -1,5 +1,3 @@ -using System; -using Content.Server.Items; using Content.Shared.Whitelist; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; diff --git a/Content.Server/Light/Components/ExpendableLightComponent.cs b/Content.Server/Light/Components/ExpendableLightComponent.cs index 2e4b05ddd2..28ba752950 100644 --- a/Content.Server/Light/Components/ExpendableLightComponent.cs +++ b/Content.Server/Light/Components/ExpendableLightComponent.cs @@ -1,6 +1,6 @@ using Content.Server.Clothing.Components; -using Content.Server.Items; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Light.Component; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -38,7 +38,7 @@ namespace Content.Server.Light.Components { base.Initialize(); - if (_entMan.TryGetComponent(Owner, out var item)) + if (_entMan.TryGetComponent(Owner, out var item)) { item.EquippedPrefix = "unlit"; } @@ -55,7 +55,7 @@ namespace Content.Server.Light.Components { if (!Activated && CurrentState == ExpendableLightState.BrandNew) { - if (_entMan.TryGetComponent(Owner, out var item)) + if (_entMan.TryGetComponent(Owner, out var item)) { item.EquippedPrefix = "lit"; } @@ -130,7 +130,7 @@ namespace Content.Server.Light.Components if (_entMan.TryGetComponent(Owner, out ClothingComponent? clothing)) { - clothing.ClothingEquippedPrefix = on ? "Activated" : string.Empty; + clothing.EquippedPrefix = on ? "Activated" : string.Empty; } } @@ -163,7 +163,7 @@ namespace Content.Server.Light.Components UpdateSpriteAndSounds(Activated); UpdateVisualizer(); - if (_entMan.TryGetComponent(Owner, out var item)) + if (_entMan.TryGetComponent(Owner, out var item)) { item.EquippedPrefix = "unlit"; } diff --git a/Content.Server/Light/Components/HandheldLightComponent.cs b/Content.Server/Light/Components/HandheldLightComponent.cs index 2c979d26a7..95fd615820 100644 --- a/Content.Server/Light/Components/HandheldLightComponent.cs +++ b/Content.Server/Light/Components/HandheldLightComponent.cs @@ -1,13 +1,27 @@ +using System.Threading.Tasks; +using Content.Server.Clothing.Components; using Content.Server.Light.EntitySystems; using Content.Server.PowerCell.Components; +using Content.Shared.ActionBlocker; +using Content.Shared.Actions; using Content.Shared.Actions.Behaviors.Item; +using Content.Shared.Examine; +using Content.Shared.Interaction; using Content.Shared.Light.Component; +using Content.Shared.Popups; +using Content.Shared.Rounding; using Content.Shared.Sound; using JetBrains.Annotations; +using Robust.Server.GameObjects; using Robust.Shared.Analyzers; +using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Player; using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.Light.Components diff --git a/Content.Server/Light/Components/MatchstickComponent.cs b/Content.Server/Light/Components/MatchstickComponent.cs index 7ae595245a..2d66607dac 100644 --- a/Content.Server/Light/Components/MatchstickComponent.cs +++ b/Content.Server/Light/Components/MatchstickComponent.cs @@ -1,7 +1,5 @@ using Content.Shared.Smoking; using Content.Shared.Sound; -using Content.Shared.Temperature; -using Content.Server.Items; using Content.Server.Light.EntitySystems; using Robust.Server.GameObjects; using Robust.Shared.Analyzers; diff --git a/Content.Server/Light/EntitySystems/HandheldLightSystem.cs b/Content.Server/Light/EntitySystems/HandheldLightSystem.cs index 67aa2ccb35..aa998b4c7c 100644 --- a/Content.Server/Light/EntitySystems/HandheldLightSystem.cs +++ b/Content.Server/Light/EntitySystems/HandheldLightSystem.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -using System.Linq; using Content.Server.Clothing.Components; -using Content.Server.Items; using Content.Server.Light.Components; using Content.Server.Popups; using Content.Server.PowerCell.Components; @@ -228,11 +226,6 @@ namespace Content.Server.Light.EntitySystems light.Enabled = on; } - if (EntityManager.TryGetComponent(component.Owner, out ClothingComponent? clothing)) - { - clothing.ClothingEquippedPrefix = Loc.GetString(on ? "on" : "off"); - } - if (EntityManager.TryGetComponent(component.Owner, out ItemComponent? item)) { item.EquippedPrefix = Loc.GetString(on ? "on" : "off"); diff --git a/Content.Server/Light/EntitySystems/MatchstickSystem.cs b/Content.Server/Light/EntitySystems/MatchstickSystem.cs index 118a7be4cc..48cb3b5ee9 100644 --- a/Content.Server/Light/EntitySystems/MatchstickSystem.cs +++ b/Content.Server/Light/EntitySystems/MatchstickSystem.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using Content.Server.Atmos.EntitySystems; -using Content.Server.Items; using Content.Server.Light.Components; using Content.Shared.Audio; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Smoking; using Content.Shared.Temperature; using Robust.Shared.Audio; @@ -90,7 +90,7 @@ namespace Content.Server.Light.EntitySystems component.PointLightComponent.Enabled = component.CurrentState == SmokableState.Lit; } - if (EntityManager.TryGetComponent(component.Owner, out ItemComponent? item)) + if (EntityManager.TryGetComponent(component.Owner, out SharedItemComponent? item)) { switch (component.CurrentState) { diff --git a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs index f5273fa553..1378bae68b 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs @@ -38,7 +38,7 @@ namespace Content.Server.Medical.SuitSensors /// Activate sensor if user wear it in this slot. /// [DataField("activationSlot")] - public EquipmentSlotDefines.Slots ActivationSlot = EquipmentSlotDefines.Slots.INNERCLOTHING; + public string ActivationSlot = "jumpsuit"; /// /// How often does sensor update its owners status (in seconds). diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index e48fded7f4..38964142da 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.ActionBlocker; using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Inventory; +using Content.Shared.Inventory.Events; using Content.Shared.Medical.SuitSensor; using Content.Shared.MobState.Components; using Content.Shared.Verbs; @@ -37,8 +38,8 @@ namespace Content.Server.Medical.SuitSensors { base.Initialize(); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnEquipped); - SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnVerb); } @@ -91,15 +92,15 @@ namespace Content.Server.Medical.SuitSensors } } - private void OnEquipped(EntityUid uid, SuitSensorComponent component, EquippedEvent args) + private void OnEquipped(EntityUid uid, SuitSensorComponent component, GotEquippedEvent args) { if (args.Slot != component.ActivationSlot) return; - component.User = args.User; + component.User = args.Equipee; } - private void OnUnequipped(EntityUid uid, SuitSensorComponent component, UnequippedEvent args) + private void OnUnequipped(EntityUid uid, SuitSensorComponent component, GotUnequippedEvent args) { if (args.Slot != component.ActivationSlot) return; @@ -216,7 +217,7 @@ namespace Content.Server.Medical.SuitSensors // try to get mobs id from ID slot var userName = Loc.GetString("suit-sensor-component-unknown-name"); var userJob = Loc.GetString("suit-sensor-component-unknown-job"); - if (_idCardSystem.TryGetIdCardSlot(sensor.User.Value, out var card)) + if (_idCardSystem.TryFindIdCard(sensor.User.Value, out var card)) { if (card.FullName != null) userName = card.FullName; diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index 79a46755bd..8089648898 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -1,12 +1,9 @@ using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; using Content.Server.DoAfter; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Nutrition.Components; using Content.Server.Popups; using Content.Shared.ActionBlocker; @@ -17,20 +14,17 @@ using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Interaction.Helpers; -using Content.Shared.Inventory; using Content.Shared.MobState.Components; -using Content.Shared.Tag; using Content.Shared.Verbs; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Player; -using System.Collections.Generic; using Robust.Shared.Utility; -using Content.Server.Inventory.Components; -using Content.Shared.Inventory; using Content.Shared.Hands; +using Content.Shared.Inventory; +using Content.Shared.Item; namespace Content.Server.Nutrition.EntitySystems { @@ -47,6 +41,7 @@ namespace Content.Server.Nutrition.EntitySystems [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedAdminLogSystem _logSystem = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; public override void Initialize() { @@ -228,7 +223,7 @@ namespace Content.Server.Nutrition.EntitySystems EntityManager.DeleteEntity((component).Owner); // Put the trash in the user's hand - if (EntityManager.TryGetComponent(finisher, out ItemComponent? item) && + if (EntityManager.TryGetComponent(finisher, out SharedItemComponent? item) && handsComponent.CanPutInHand(item)) { handsComponent.PutInHand(item); @@ -485,20 +480,20 @@ namespace Content.Server.Nutrition.EntitySystems IngestionBlockerComponent blocker; - if (component.TryGetSlotItem(EquipmentSlotDefines.Slots.MASK, out ItemComponent? mask) && - EntityManager.TryGetComponent(mask.Owner, out blocker) && + if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) && + EntityManager.TryGetComponent(maskUid, out blocker) && blocker.Enabled) { - args.Blocker = mask.Owner; + args.Blocker = maskUid; args.Cancel(); return; } - if (component.TryGetSlotItem(EquipmentSlotDefines.Slots.HEAD, out ItemComponent? head) && - EntityManager.TryGetComponent(head.Owner, out blocker) && + if (_inventorySystem.TryGetSlotEntity(uid, "head", out var headUid) && + EntityManager.TryGetComponent(headUid, out blocker) && blocker.Enabled) { - args.Blocker = head.Owner; + args.Blocker = headUid; args.Cancel(); } } diff --git a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs index e8ef70d63a..965fdbfc18 100644 --- a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs @@ -1,12 +1,12 @@ using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Nutrition.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Interaction; +using Content.Shared.Item; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -69,7 +69,7 @@ namespace Content.Server.Nutrition.EntitySystems { if (ContainerHelpers.IsInContainer(component.Owner)) { - handsComponent.PutInHandOrDrop(EntityManager.GetComponent(sliceUid)); + handsComponent.PutInHandOrDrop(EntityManager.GetComponent(sliceUid)); } } diff --git a/Content.Server/PDA/PDAExtensions.cs b/Content.Server/PDA/PDAExtensions.cs index 23c5ffc0ce..dd37b9c14d 100644 --- a/Content.Server/PDA/PDAExtensions.cs +++ b/Content.Server/PDA/PDAExtensions.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; using Content.Shared.Access.Components; +using Content.Shared.Inventory; using Content.Shared.PDA; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -18,7 +18,7 @@ namespace Content.Server.PDA /// The id card component. public static IdCardComponent? GetHeldId(this EntityUid player) { - IdCardComponent? firstIdInPda = null; + IdCardComponent? foundPDAId = null; var entMan = IoCManager.Resolve(); @@ -26,11 +26,10 @@ namespace Content.Server.PDA { foreach (var item in hands.GetAllHeldItems()) { - if (firstIdInPda == null && - entMan.TryGetComponent(item.Owner, out PDAComponent? pda) && + if (entMan.TryGetComponent(item.Owner, out PDAComponent? pda) && pda.ContainedID != null) { - firstIdInPda = pda.ContainedID; + foundPDAId = pda.ContainedID; } if (entMan.TryGetComponent(item.Owner, out IdCardComponent? card)) @@ -40,32 +39,32 @@ namespace Content.Server.PDA } } - if (firstIdInPda != null) - { - return firstIdInPda; - } + if (foundPDAId != null) return foundPDAId; - IdCardComponent? firstIdInInventory = null; + var invSystem = EntitySystem.Get(); - if (entMan.TryGetComponent(player, out InventoryComponent? inventory)) + if (invSystem.TryGetContainerSlotEnumerator(player, out var enumerator)) { - foreach (var item in inventory.GetAllHeldItems()) + while (enumerator.MoveNext(out var containerSlot)) { - if (firstIdInInventory == null && - entMan.TryGetComponent(item, out PDAComponent? pda) && + if(!containerSlot.ContainedEntity.HasValue) continue; + + if (entMan.TryGetComponent(containerSlot.ContainedEntity.Value, out PDAComponent? pda) && pda.ContainedID != null) { - firstIdInInventory = pda.ContainedID; + foundPDAId = pda.ContainedID; } - if (entMan.TryGetComponent(item, out IdCardComponent? card)) + if (entMan.TryGetComponent(containerSlot.ContainedEntity.Value, out IdCardComponent? card)) { return card; } } } - return firstIdInInventory; + if (foundPDAId != null) return foundPDAId; + + return null; } /// diff --git a/Content.Server/Physics/Controllers/MoverController.cs b/Content.Server/Physics/Controllers/MoverController.cs index 21ee487a22..cd4f04e1eb 100644 --- a/Content.Server/Physics/Controllers/MoverController.cs +++ b/Content.Server/Physics/Controllers/MoverController.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Movement.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.EntitySystems; using Content.Shared.CCVar; using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.Maps; using Content.Shared.Movement; using Content.Shared.Movement.Components; @@ -302,9 +301,10 @@ namespace Content.Server.Physics.Controllers mobMover.StepSoundDistance -= distanceNeeded; - if (EntityManager.TryGetComponent(mover.Owner, out var inventory) - && inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.SHOES, out var item) - && EntityManager.TryGetComponent(item.Owner, out var modifier)) + var invSystem = EntitySystem.Get(); + + if (invSystem.TryGetSlotEntity(mover.Owner, "shoes", out var shoes) && + EntityManager.TryGetComponent(shoes, out var modifier)) { modifier.PlayFootstep(); } diff --git a/Content.Server/PneumaticCannon/PneumaticCannonSystem.cs b/Content.Server/PneumaticCannon/PneumaticCannonSystem.cs index ae8382154f..b33e395830 100644 --- a/Content.Server/PneumaticCannon/PneumaticCannonSystem.cs +++ b/Content.Server/PneumaticCannon/PneumaticCannonSystem.cs @@ -4,7 +4,6 @@ using System.Linq; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Nutrition.Components; using Content.Server.Storage.Components; using Content.Server.Stunnable; @@ -13,6 +12,7 @@ using Content.Server.Tools.Components; using Content.Shared.Camera; using Content.Shared.CombatMode; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.PneumaticCannon; using Content.Shared.Popups; using Content.Shared.StatusEffect; @@ -134,7 +134,7 @@ namespace Content.Server.PneumaticCannon // this overrides the ServerStorageComponent's insertion stuff because // it's not event-based yet and I can't cancel it, so tools and stuff // will modify mode/power then get put in anyway - if (EntityManager.TryGetComponent(args.Used, out var item) + if (EntityManager.TryGetComponent(args.Used, out var item) && EntityManager.TryGetComponent(component.Owner, out var storage)) { if (storage.CanInsert(args.Used)) diff --git a/Content.Server/Power/Components/BaseCharger.cs b/Content.Server/Power/Components/BaseCharger.cs index e874bf6b07..6066077652 100644 --- a/Content.Server/Power/Components/BaseCharger.cs +++ b/Content.Server/Power/Components/BaseCharger.cs @@ -1,9 +1,9 @@ using System; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Weapon.Ranged.Barrels.Components; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Power; using Robust.Shared.Containers; @@ -101,7 +101,7 @@ namespace Content.Server.Power.Components _heldBattery = null; if (_entMan.TryGetComponent(user, out HandsComponent? handsComponent)) { - handsComponent.PutInHandOrDrop(_entMan.GetComponent(heldItem)); + handsComponent.PutInHandOrDrop(_entMan.GetComponent(heldItem)); } if (_entMan.TryGetComponent(heldItem, out ServerBatteryBarrelComponent? batteryBarrelComponent)) diff --git a/Content.Server/Power/SetBatteryPercentCommand.cs b/Content.Server/Power/SetBatteryPercentCommand.cs index 5fff0ca941..908cc2e5cc 100644 --- a/Content.Server/Power/SetBatteryPercentCommand.cs +++ b/Content.Server/Power/SetBatteryPercentCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Administration; using Content.Server.Power.Components; -using Content.Server.Items; using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.GameObjects; diff --git a/Content.Server/PowerCell/Components/PowerCellSlotComponent.cs b/Content.Server/PowerCell/Components/PowerCellSlotComponent.cs index e84d0b46ad..d8e8cc7216 100644 --- a/Content.Server/PowerCell/Components/PowerCellSlotComponent.cs +++ b/Content.Server/PowerCell/Components/PowerCellSlotComponent.cs @@ -1,8 +1,8 @@ using System; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Shared.Audio; using Content.Shared.Examine; +using Content.Shared.Item; using Content.Shared.Sound; using Robust.Shared.Audio; using Robust.Shared.Containers; @@ -136,7 +136,7 @@ namespace Content.Server.PowerCell.Components //Dirty(); if (user != null) { - if (!_entities.TryGetComponent(user, out HandsComponent? hands) || !hands.PutInHand(_entities.GetComponent(cell.Owner))) + if (!_entities.TryGetComponent(user, out HandsComponent? hands) || !hands.PutInHand(_entities.GetComponent(cell.Owner))) { _entities.GetComponent(cell.Owner).Coordinates = _entities.GetComponent(user.Value).Coordinates; } @@ -164,7 +164,7 @@ namespace Content.Server.PowerCell.Components public bool InsertCell(EntityUid cell, bool playSound = true) { if (Cell != null) return false; - if (!_entities.HasComponent(cell)) return false; + if (!_entities.HasComponent(cell)) return false; if (!_entities.TryGetComponent(cell, out var cellComponent)) return false; if (cellComponent.CellSize != SlotSize) return false; if (!_cellContainer.Insert(cell)) return false; diff --git a/Content.Server/Sandbox/SandboxManager.cs b/Content.Server/Sandbox/SandboxManager.cs index 0c7eef4cc2..cee8cbbfc8 100644 --- a/Content.Server/Sandbox/SandboxManager.cs +++ b/Content.Server/Sandbox/SandboxManager.cs @@ -1,12 +1,12 @@ using System.Linq; using Content.Server.GameTicking; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Shared.Access; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; +using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.PDA; using Content.Shared.Sandbox; using Robust.Server.Console; @@ -19,7 +19,6 @@ using Robust.Shared.IoC; using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Server.Sandbox { @@ -124,14 +123,15 @@ namespace Content.Server.Sandbox .EnumeratePrototypes() .Select(p => p.ID).ToArray(); - if (_entityManager.TryGetComponent(attached, out InventoryComponent? inv) - && inv.TryGetSlotItem(Slots.IDCARD, out ItemComponent? wornItem)) + var invSystem = EntitySystem.Get(); + + if (invSystem.TryGetSlotEntity(attached, "id", out var slotEntity)) { - if (_entityManager.HasComponent(wornItem.Owner)) + if (_entityManager.HasComponent(slotEntity)) { - UpgradeId(wornItem.Owner); + UpgradeId(slotEntity.Value); } - else if (_entityManager.TryGetComponent(wornItem.Owner, out PDAComponent? pda)) + else if (_entityManager.TryGetComponent(slotEntity, out PDAComponent? pda)) { if (pda.ContainedID == null) { @@ -139,7 +139,7 @@ namespace Content.Server.Sandbox if (_entityManager.TryGetComponent(pda.Owner, out ItemSlotsComponent? itemSlots)) { _entityManager.EntitySysManager.GetEntitySystem(). - TryInsert(wornItem.Owner, pda.IdSlot, newID, null); + TryInsert(slotEntity.Value, pda.IdSlot, newID, null); } } else @@ -151,9 +151,9 @@ namespace Content.Server.Sandbox else if (_entityManager.TryGetComponent(attached, out var hands)) { var card = CreateFreshId(); - if (!_entityManager.TryGetComponent(attached, out inv) || !inv.Equip(Slots.IDCARD, card)) + if (!invSystem.TryEquip(attached, card, "id", true, true)) { - hands.PutInHandOrDrop(_entityManager.GetComponent(card)); + hands.PutInHandOrDrop(_entityManager.GetComponent(card)); } } diff --git a/Content.Server/Stack/StackSystem.cs b/Content.Server/Stack/StackSystem.cs index c4e9817e16..0db324eb08 100644 --- a/Content.Server/Stack/StackSystem.cs +++ b/Content.Server/Stack/StackSystem.cs @@ -1,8 +1,8 @@ using System; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Popups; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Stacks; using Content.Shared.Verbs; using JetBrains.Annotations; @@ -180,7 +180,7 @@ namespace Content.Server.Stack if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split) return; - if (TryComp(userUid, out var hands) && TryComp(split, out var item)) + if (TryComp(userUid, out var hands) && TryComp(split, out var item)) { hands.PutInHandOrDrop(item); } diff --git a/Content.Server/Storage/Components/ServerStorageComponent.cs b/Content.Server/Storage/Components/ServerStorageComponent.cs index 12ec21c6d6..d749f93f37 100644 --- a/Content.Server/Storage/Components/ServerStorageComponent.cs +++ b/Content.Server/Storage/Components/ServerStorageComponent.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Content.Server.DoAfter; using Content.Server.Hands.Components; using Content.Server.Interaction; -using Content.Server.Items; using Content.Shared.Acts; using Content.Shared.Interaction; using Content.Shared.Interaction.Helpers; @@ -471,7 +470,7 @@ namespace Content.Server.Storage.Components break; } - if (!_entityManager.TryGetComponent(remove.EntityUid, out ItemComponent? item) || !_entityManager.TryGetComponent(player, out HandsComponent? hands)) + if (!_entityManager.TryGetComponent(remove.EntityUid, out SharedItemComponent? item) || !_entityManager.TryGetComponent(player, out HandsComponent? hands)) { break; } diff --git a/Content.Server/Storage/EntitySystems/SecretStashSystem.cs b/Content.Server/Storage/EntitySystems/SecretStashSystem.cs index fa19fce286..6c23e64cb4 100644 --- a/Content.Server/Storage/EntitySystems/SecretStashSystem.cs +++ b/Content.Server/Storage/EntitySystems/SecretStashSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Items; +using Content.Server.Clothing.Components; using Content.Server.Popups; using Content.Server.Storage.Components; using Content.Shared.Acts; diff --git a/Content.Server/Strip/StrippableComponent.cs b/Content.Server/Strip/StrippableComponent.cs index 2222f83238..bc1b9ca14d 100644 --- a/Content.Server/Strip/StrippableComponent.cs +++ b/Content.Server/Strip/StrippableComponent.cs @@ -3,36 +3,38 @@ using System.Threading; using Content.Server.Cuffs.Components; using Content.Server.DoAfter; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; +using Content.Server.Inventory; using Content.Server.UserInterface; using Content.Shared.ActionBlocker; using Content.Shared.DragDrop; using Content.Shared.Hands.Components; +using Content.Shared.Inventory; using Content.Shared.Popups; using Content.Shared.Strip.Components; using Robust.Server.GameObjects; using Robust.Server.Player; +using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Server.Strip { [RegisterComponent] [ComponentReference(typeof(SharedStrippableComponent))] + [Friend(typeof(StrippableSystem))] public sealed class StrippableComponent : SharedStrippableComponent { [Dependency] private readonly IEntityManager _entities = default!; + private StrippableSystem _strippableSystem = default!; public const float StripDelay = 2f; // TODO: This component needs localization. [ViewVariables] - private BoundUserInterface? UserInterface => Owner.GetUIOrNull(StrippingUiKey.Key); + public BoundUserInterface? UserInterface => Owner.GetUIOrNull(StrippingUiKey.Key); protected override void Initialize() { @@ -43,41 +45,27 @@ namespace Content.Server.Strip UserInterface.OnReceiveMessage += HandleUserInterfaceMessage; } - Owner.EnsureComponentWarn(); - Owner.EnsureComponentWarn(); - Owner.EnsureComponentWarn(); - - if (_entities.TryGetComponent(Owner, out CuffableComponent? cuffed)) - { - cuffed.OnCuffedStateChanged += UpdateSubscribed; - } - - if (_entities.TryGetComponent(Owner, out InventoryComponent? inventory)) - { - inventory.OnItemChanged += UpdateSubscribed; - } - - if (_entities.TryGetComponent(Owner, out HandsComponent? hands)) - { - hands.OnItemChanged += UpdateSubscribed; - } - - // Initial update. - UpdateSubscribed(); + _strippableSystem = EntitySystem.Get(); + Owner.EnsureComponentWarn(); + var hands = Owner.EnsureComponentWarn(); + var cuffed = Owner.EnsureComponentWarn(); + cuffed.OnCuffedStateChanged += UpdateState; + hands.OnItemChanged += UpdateState; } - private void UpdateSubscribed() + protected override void Shutdown() { - if (UserInterface == null) - { - return; - } + base.Shutdown(); - var inventory = GetInventorySlots(); - var hands = GetHandSlots(); - var cuffs = GetHandcuffs(); + if(_entities.TryGetComponent(Owner, out var hands)) + hands.OnItemChanged -= UpdateState; + if(_entities.TryGetComponent(Owner, out var cuffed)) + cuffed.OnCuffedStateChanged -= UpdateState; + } - UserInterface.SetState(new StrippingBoundUserInterfaceState(inventory, hands, cuffs)); + private void UpdateState() + { + _strippableSystem.SendUpdate(Owner, this); } public override bool Drop(DragDropEvent args) @@ -88,71 +76,6 @@ namespace Content.Server.Strip return true; } - private Dictionary GetHandcuffs() - { - var dictionary = new Dictionary(); - - if (!_entities.TryGetComponent(Owner, out CuffableComponent? cuffed)) - { - return dictionary; - } - - foreach (var entity in cuffed.StoredEntities) - { - var name = _entities.GetComponent(entity).EntityName; - dictionary.Add(entity, name); - } - - return dictionary; - } - - private Dictionary GetInventorySlots() - { - var dictionary = new Dictionary(); - - if (!_entities.TryGetComponent(Owner, out InventoryComponent? inventory)) - { - return dictionary; - } - - foreach (var slot in inventory.Slots) - { - var name = "None"; - - if (inventory.GetSlotItem(slot) is { } item) - name = _entities.GetComponent(item.Owner).EntityName; - - dictionary[slot] = name; - } - - return dictionary; - } - - private Dictionary GetHandSlots() - { - var dictionary = new Dictionary(); - - if (!_entities.TryGetComponent(Owner, out HandsComponent? hands)) - { - return dictionary; - } - - foreach (var hand in hands.HandNames) - { - var owner = hands.GetItem(hand)?.Owner; - - if (!owner.HasValue || _entities.HasComponent(owner.Value)) - { - dictionary[hand] = "None"; - continue; - } - - dictionary[hand] = _entities.GetComponent(owner.Value).EntityName; - } - - return dictionary; - } - public void OpenUserInterface(IPlayerSession session) { UserInterface?.Open(session); @@ -161,11 +84,11 @@ namespace Content.Server.Strip /// /// Places item in user's active hand to an inventory slot. /// - private async void PlaceActiveHandItemInInventory(EntityUid user, Slots slot) + private async void PlaceActiveHandItemInInventory(EntityUid user, string slot) { - var inventory = _entities.GetComponent(Owner); var userHands = _entities.GetComponent(user); var item = userHands.GetActiveHand; + var invSystem = EntitySystem.Get(); bool Check() { @@ -184,16 +107,16 @@ namespace Content.Server.Strip return false; } - if (!inventory.HasSlot(slot)) + if (!invSystem.HasSlot(Owner, slot)) return false; - if (inventory.TryGetSlotItem(slot, out ItemComponent? _)) + if (invSystem.TryGetSlotEntity(Owner, slot, out _)) { user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-occupied",("owner", Owner))); return false; } - if (!inventory.CanEquip(slot, item, false)) + if (!invSystem.CanEquip(Owner, item.Owner, slot, out _)) { user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-equip-message",("owner", Owner))); return false; @@ -218,9 +141,9 @@ namespace Content.Server.Strip if (result != DoAfterStatus.Finished) return; userHands.Drop(item!.Owner, false); - inventory.Equip(slot, item!.Owner, false); + invSystem.TryEquip(Owner, item.Owner, slot); - UpdateSubscribed(); + UpdateState(); } /// @@ -286,32 +209,33 @@ namespace Content.Server.Strip userHands.Drop(hand); hands.TryPickupEntity(hand, item!.Owner, checkActionBlocker: false); - UpdateSubscribed(); + UpdateState(); } /// /// Takes an item from the inventory and places it in the user's active hand. /// - private async void TakeItemFromInventory(EntityUid user, Slots slot) + private async void TakeItemFromInventory(EntityUid user, string slot) { var inventory = _entities.GetComponent(Owner); var userHands = _entities.GetComponent(user); + var invSystem = EntitySystem.Get(); bool Check() { if (!EntitySystem.Get().CanInteract(user)) return false; - if (!inventory.HasSlot(slot)) + if (!invSystem.HasSlot(Owner, slot)) return false; - if (!inventory.TryGetSlotItem(slot, out ItemComponent? itemToTake)) + if (!invSystem.TryGetSlotEntity(Owner, slot, out var item)) { user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-free-message",("owner", Owner))); return false; } - if (!inventory.CanUnequip(slot, false)) + if (!invSystem.CanUnequip(Owner, slot, out _)) { user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-unequip-message",("owner", Owner))); return false; @@ -334,15 +258,15 @@ namespace Content.Server.Strip var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; - var item = inventory.GetSlotItem(slot); - inventory.Unequip(slot, false); + invSystem.TryGetSlotEntity(Owner, slot, out var item); + invSystem.TryUnequip(Owner, slot); if (item != null) { - userHands.PutInHandOrDrop(item); + userHands.PutInHandOrDrop(item.Value); } - UpdateSubscribed(); + UpdateState(); } /// @@ -396,7 +320,7 @@ namespace Content.Server.Strip var item = hands.GetItem(hand); hands.Drop(hand, false); userHands.PutInHandOrDrop(item!); - UpdateSubscribed(); + UpdateState(); } private void HandleUserInterfaceMessage(ServerBoundUserInterfaceMessage obj) @@ -410,10 +334,9 @@ namespace Content.Server.Strip switch (obj.Message) { case StrippingInventoryButtonPressed inventoryMessage: - if (_entities.TryGetComponent(Owner, out var inventory)) { - if (inventory.TryGetSlotItem(inventoryMessage.Slot, out ItemComponent? _)) + if (EntitySystem.Get().TryGetSlotEntity(Owner, inventoryMessage.Slot, out _, inventory)) placingItem = false; if (placingItem) diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index 5a8039c83f..9d7a1f5d4d 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -1,3 +1,10 @@ +using System.Collections.Generic; +using Content.Server.Cuffs.Components; +using Content.Server.Hands.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Inventory; +using Content.Shared.Inventory.Events; +using Content.Shared.Strip.Components; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; @@ -8,11 +15,82 @@ namespace Content.Server.Strip { public sealed class StrippableSystem : EntitySystem { + [Dependency] private readonly InventorySystem _inventorySystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(AddStripVerb); + SubscribeLocalEvent(OnDidEquip); + SubscribeLocalEvent(OnDidUnequip); + SubscribeLocalEvent(OnCompInit); + } + + private void OnCompInit(EntityUid uid, StrippableComponent component, ComponentInit args) + { + SendUpdate(uid, component); + } + + private void OnDidUnequip(EntityUid uid, StrippableComponent component, DidUnequipEvent args) + { + SendUpdate(uid, component); + } + + private void OnDidEquip(EntityUid uid, StrippableComponent component, DidEquipEvent args) + { + SendUpdate(uid, component); + } + + public void SendUpdate(EntityUid uid, StrippableComponent? strippableComponent = null) + { + if (!Resolve(uid, ref strippableComponent) || strippableComponent.UserInterface == null) + { + return; + } + + var cuffs = new Dictionary(); + var inventory = new Dictionary<(string ID, string Name), string>(); + var hands = new Dictionary(); + + if (TryComp(uid, out CuffableComponent? cuffed)) + { + foreach (var entity in cuffed.StoredEntities) + { + var name = Name(entity); + cuffs.Add(entity, name); + } + } + + if (_inventorySystem.TryGetSlots(uid, out var slots)) + { + foreach (var slot in slots) + { + var name = "None"; + + if (_inventorySystem.TryGetSlotEntity(uid, slot.Name, out var item)) + name = Name(item.Value); + + inventory[(slot.Name, slot.DisplayName)] = name; + } + } + + if (TryComp(uid, out HandsComponent? handsComp)) + { + foreach (var hand in handsComp.HandNames) + { + var owner = handsComp.GetItem(hand)?.Owner; + + if (!owner.HasValue || HasComp(owner.Value)) + { + hands[hand] = "None"; + continue; + } + + hands[hand] = Name(owner.Value); + } + } + + strippableComponent.UserInterface.SetState(new StrippingBoundUserInterfaceState(inventory, hands, cuffs)); } private void AddStripVerb(EntityUid uid, StrippableComponent component, GetOtherVerbsEvent args) diff --git a/Content.Server/Stunnable/StunbatonSystem.cs b/Content.Server/Stunnable/StunbatonSystem.cs index 9fec34edc2..15576ee10b 100644 --- a/Content.Server/Stunnable/StunbatonSystem.cs +++ b/Content.Server/Stunnable/StunbatonSystem.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using Content.Server.Items; using Content.Server.PowerCell.Components; using Content.Server.Speech.EntitySystems; using Content.Server.Stunnable.Components; @@ -9,6 +8,7 @@ using Content.Shared.ActionBlocker; using Content.Shared.Audio; using Content.Shared.Examine; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Jittering; using Content.Shared.Popups; using Content.Shared.StatusEffect; @@ -159,7 +159,7 @@ namespace Content.Server.Stunnable } if (!EntityManager.TryGetComponent(comp.Owner, out var sprite) || - !EntityManager.TryGetComponent(comp.Owner, out var item)) return; + !EntityManager.TryGetComponent(comp.Owner, out var item)) return; SoundSystem.Play(Filter.Pvs(comp.Owner), comp.SparksSound.GetSound(), comp.Owner, AudioHelpers.WithVariation(0.25f)); item.EquippedPrefix = "off"; @@ -176,7 +176,7 @@ namespace Content.Server.Stunnable } if (!EntityManager.TryGetComponent(comp.Owner, out var sprite) || - !EntityManager.TryGetComponent(comp.Owner, out var item)) + !EntityManager.TryGetComponent(comp.Owner, out var item)) return; var playerFilter = Filter.Pvs(comp.Owner); diff --git a/Content.Server/Temperature/Components/HeatResistanceComponent.cs b/Content.Server/Temperature/Components/HeatResistanceComponent.cs index b3cc28da7b..071e35901f 100644 --- a/Content.Server/Temperature/Components/HeatResistanceComponent.cs +++ b/Content.Server/Temperature/Components/HeatResistanceComponent.cs @@ -1,5 +1,4 @@ using Content.Server.Clothing.Components; -using Content.Server.Inventory.Components; using Content.Shared.Inventory; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -15,15 +14,10 @@ namespace Content.Server.Temperature.Components { // TODO: When making into system: Any animal that touches bulb that has no // InventoryComponent but still would have default heat resistance in the future (maybe) - if (!IoCManager.Resolve().TryGetComponent(Owner, out var inventoryComp)) + if (EntitySystem.Get().TryGetSlotEntity(Owner, "gloves", out var slotEntity) && + IoCManager.Resolve().TryGetComponent(slotEntity, out var gloves)) { - // Magical number just copied from below - return int.MinValue; - } - - if (inventoryComp.TryGetSlotItem(EquipmentSlotDefines.Slots.GLOVES, out ClothingComponent? gloves)) - { - return gloves?.HeatResistance ?? int.MinValue; + return gloves.HeatResistance; } return int.MinValue; } diff --git a/Content.Server/Throwing/ThrowHelper.cs b/Content.Server/Throwing/ThrowHelper.cs index c962a2ac40..d8d3f8bd5c 100644 --- a/Content.Server/Throwing/ThrowHelper.cs +++ b/Content.Server/Throwing/ThrowHelper.cs @@ -1,6 +1,6 @@ using System; using Content.Server.Interaction; -using Content.Server.Items; +using Content.Shared.Item; using Content.Shared.MobState.Components; using Content.Shared.Tag; using Content.Shared.Throwing; @@ -54,7 +54,7 @@ namespace Content.Server.Throwing } var comp = entity.EnsureComponent(); - if (entities.HasComponent(entity)) + if (entities.HasComponent(entity)) { comp.Thrower = user; // Give it a l'il spin. diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs index 3e0a3f1365..cb290ef118 100644 --- a/Content.Server/Tools/ToolSystem.Welder.cs +++ b/Content.Server/Tools/ToolSystem.Welder.cs @@ -1,16 +1,15 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; -using Content.Server.Items; using Content.Server.Tools.Components; using Content.Server.Weapon.Melee; using Content.Shared.Audio; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Temperature; using Content.Shared.Tools.Components; @@ -64,7 +63,7 @@ namespace Content.Server.Tools public bool TryToggleWelder(EntityUid uid, EntityUid? user, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null, - ItemComponent? item = null, + SharedItemComponent? item = null, PointLightComponent? light = null, SpriteComponent? sprite = null) { @@ -81,7 +80,7 @@ namespace Content.Server.Tools public bool TryTurnWelderOn(EntityUid uid, EntityUid? user, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null, - ItemComponent? item = null, + SharedItemComponent? item = null, PointLightComponent? light = null, SpriteComponent? sprite = null) { @@ -132,7 +131,7 @@ namespace Content.Server.Tools public bool TryTurnWelderOff(EntityUid uid, EntityUid? user, WelderComponent? welder = null, - ItemComponent? item = null, + SharedItemComponent? item = null, PointLightComponent? light = null, SpriteComponent? sprite = null) { diff --git a/Content.Server/Traitor/Uplink/UplinkSystem.cs b/Content.Server/Traitor/Uplink/UplinkSystem.cs index 2e3bcb2915..6d9d1ba008 100644 --- a/Content.Server/Traitor/Uplink/UplinkSystem.cs +++ b/Content.Server/Traitor/Uplink/UplinkSystem.cs @@ -1,13 +1,13 @@ using System.Linq; using Content.Server.Hands.Components; -using Content.Server.Inventory.Components; -using Content.Server.Items; using Content.Server.Traitor.Uplink.Account; using Content.Server.Traitor.Uplink.Components; using Content.Server.UserInterface; using Content.Shared.ActionBlocker; using Content.Shared.Hands.Components; using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.PDA; using Content.Shared.Traitor.Uplink; using Robust.Server.GameObjects; @@ -27,6 +27,8 @@ namespace Content.Server.Traitor.Uplink [Dependency] private readonly UplinkListingSytem _listing = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + public override void Initialize() { base.Initialize(); @@ -126,7 +128,7 @@ namespace Content.Server.Traitor.Uplink } if (EntityManager.TryGetComponent(player, out HandsComponent? hands) && - EntityManager.TryGetComponent(entity.Value, out ItemComponent? item)) + EntityManager.TryGetComponent(entity.Value, out SharedItemComponent? item)) { hands.PutInHandOrDrop(item); } @@ -206,11 +208,16 @@ namespace Content.Server.Traitor.Uplink private EntityUid? FindUplinkTarget(EntityUid user) { // Try to find PDA in inventory - if (EntityManager.TryGetComponent(user, out InventoryComponent? inventory)) + + if (_inventorySystem.TryGetContainerSlotEnumerator(user, out var containerSlotEnumerator)) { - var foundPDA = inventory.LookupItems().FirstOrDefault(); - if (foundPDA != null) - return foundPDA.Owner; + while (containerSlotEnumerator.MoveNext(out var pdaUid)) + { + if(!pdaUid.ContainedEntity.HasValue) continue; + + if(HasComp(pdaUid.ContainedEntity.Value)) + return pdaUid.ContainedEntity.Value; + } } // Also check hands diff --git a/Content.Server/TraitorDeathMatch/Components/TraitorDeathMatchRedemptionComponent.cs b/Content.Server/TraitorDeathMatch/Components/TraitorDeathMatchRedemptionComponent.cs index 12fea6870f..51541f5181 100644 --- a/Content.Server/TraitorDeathMatch/Components/TraitorDeathMatchRedemptionComponent.cs +++ b/Content.Server/TraitorDeathMatch/Components/TraitorDeathMatchRedemptionComponent.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using Content.Server.Inventory.Components; using Content.Server.Mind.Components; using Content.Server.Traitor.Uplink.Account; using Content.Server.Traitor.Uplink.Components; @@ -9,6 +8,7 @@ using Content.Shared.Popups; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; +using InventoryComponent = Content.Shared.Inventory.InventoryComponent; namespace Content.Server.TraitorDeathMatch.Components { @@ -22,13 +22,6 @@ namespace Content.Server.TraitorDeathMatch.Components async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { - if (!_entMan.TryGetComponent(eventArgs.User, out var userInv)) - { - Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-main-message", - ("secondMessage", Loc.GetString("traitor-death-match-redemption-component-interact-using-no-inventory-message")))); - return false; - } - if (!_entMan.TryGetComponent(eventArgs.User, out var userMindComponent)) { Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-main-message", @@ -66,10 +59,13 @@ namespace Content.Server.TraitorDeathMatch.Components } UplinkComponent? userUplink = null; + var invSystem = EntitySystem.Get(); - if (userInv.GetSlotItem(EquipmentSlotDefines.Slots.IDCARD)?.Owner is {Valid: true} userPDAEntity) - if (_entMan.TryGetComponent(userPDAEntity, out var userUplinkComponent)) - userUplink = userUplinkComponent; + if (invSystem.TryGetSlotEntity(eventArgs.User, "id", out var pdaUid) && + _entMan.TryGetComponent(pdaUid, out var userUplinkComponent)) + { + userUplink = userUplinkComponent; + } if (userUplink == null) { diff --git a/Content.Server/Weapon/Ranged/Ammunition/Components/RangedMagazineComponent.cs b/Content.Server/Weapon/Ranged/Ammunition/Components/RangedMagazineComponent.cs index bce774c4d6..0008758e23 100644 --- a/Content.Server/Weapon/Ranged/Ammunition/Components/RangedMagazineComponent.cs +++ b/Content.Server/Weapon/Ranged/Ammunition/Components/RangedMagazineComponent.cs @@ -2,10 +2,10 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Weapon.Ranged.Barrels.Components; using Content.Shared.Examine; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Weapons.Ranged.Barrels.Components; using Robust.Shared.Containers; @@ -156,7 +156,7 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components return false; } - var itemComponent = _entities.GetComponent(ammo); + var itemComponent = _entities.GetComponent(ammo); if (!handsComponent.CanPutInHand(itemComponent)) { _entities.GetComponent(ammo).Coordinates = _entities.GetComponent(eventArgs.User).Coordinates; diff --git a/Content.Server/Weapon/Ranged/Ammunition/Components/SpeedLoaderComponent.cs b/Content.Server/Weapon/Ranged/Ammunition/Components/SpeedLoaderComponent.cs index bb2bd804d6..07b12e1af8 100644 --- a/Content.Server/Weapon/Ranged/Ammunition/Components/SpeedLoaderComponent.cs +++ b/Content.Server/Weapon/Ranged/Ammunition/Components/SpeedLoaderComponent.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Weapon.Ranged.Barrels.Components; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Weapons.Ranged.Barrels.Components; using Robust.Shared.Containers; @@ -110,7 +110,7 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components return false; } - var itemComponent = _entMan.GetComponent(ammo); + var itemComponent = _entMan.GetComponent(ammo); if (!handsComponent.CanPutInHand(itemComponent)) { ServerRangedBarrelComponent.EjectCasing(ammo); diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs index 1a5c920db5..411c6615de 100644 --- a/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs +++ b/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs @@ -2,10 +2,10 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Weapon.Ranged.Ammunition.Components; using Content.Shared.Examine; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Sound; using Content.Shared.Weapons.Ranged; @@ -340,7 +340,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components if (_entities.TryGetComponent(user, out HandsComponent? handsComponent)) { - handsComponent.PutInHandOrDrop(_entities.GetComponent(mag.Value)); + handsComponent.PutInHandOrDrop(_entities.GetComponent(mag.Value)); } Dirty(); diff --git a/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs b/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs index e93cc22db2..fd00331f88 100644 --- a/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs +++ b/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Content.Server.Clothing.Components; using Content.Server.Hands.Components; -using Content.Server.Items; using Content.Server.Weapon.Ranged.Ammunition.Components; using Content.Server.Weapon.Ranged.Barrels.Components; using Content.Shared.Examine; diff --git a/Content.Server/Wieldable/WieldableSystem.cs b/Content.Server/Wieldable/WieldableSystem.cs index 4e3a395645..4edfb8a905 100644 --- a/Content.Server/Wieldable/WieldableSystem.cs +++ b/Content.Server/Wieldable/WieldableSystem.cs @@ -1,11 +1,11 @@ using Content.Server.DoAfter; using Content.Server.Hands.Components; using Content.Server.Hands.Systems; -using Content.Server.Items; using Content.Server.Weapon.Melee; using Content.Server.Wieldable.Components; using Content.Shared.Hands; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Shared.Audio; @@ -157,7 +157,7 @@ namespace Content.Server.Wieldable if (!CanWield(uid, component, args.User.Value) || component.Wielded) return; - if (EntityManager.TryGetComponent(uid, out var item)) + if (TryComp(uid, out var item)) { component.OldInhandPrefix = item.EquippedPrefix; item.EquippedPrefix = component.WieldedInhandPrefix; @@ -186,7 +186,7 @@ namespace Content.Server.Wieldable if (!component.Wielded) return; - if (EntityManager.TryGetComponent(uid, out var item)) + if (TryComp(uid, out var item)) { item.EquippedPrefix = component.OldInhandPrefix; } diff --git a/Content.Server/WireHacking/WiresComponent.cs b/Content.Server/WireHacking/WiresComponent.cs index d9acca8305..4babcb9a19 100644 --- a/Content.Server/WireHacking/WiresComponent.cs +++ b/Content.Server/WireHacking/WiresComponent.cs @@ -425,7 +425,7 @@ namespace Content.Server.WireHacking } ToolComponent? tool = null; - if (handsComponent.GetActiveHand?.Owner is {Valid: true} activeHandEntity) + if (handsComponent.GetActiveHand?.Owner is EntityUid activeHandEntity) _entities.TryGetComponent(activeHandEntity, out tool); var toolSystem = EntitySystem.Get(); diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index 1c840d715f..f604030b69 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -2,11 +2,10 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Content.Shared.Access.Components; using Content.Shared.Hands.Components; using Content.Shared.Inventory; -using Content.Shared.Item; using Content.Shared.PDA; +using Content.Shared.Access.Components; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -17,6 +16,7 @@ namespace Content.Shared.Access.Systems public class AccessReaderSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; public override void Initialize() { @@ -78,15 +78,8 @@ namespace Content.Shared.Access.Systems } // maybe its inside an inventory slot? - if (EntityManager.TryGetComponent(uid, out SharedInventoryComponent? inventoryComponent)) - { - if (inventoryComponent.TryGetSlot(EquipmentSlotDefines.Slots.IDCARD, out var entity) && - FindAccessTagsItem(entity.Value, out tags) - ) - { - return tags; - } - } + if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && FindAccessTagsItem(idUid.Value, out tags)) + return tags; return Array.Empty(); } diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index 761780a0a0..a919038bf5 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -90,22 +90,6 @@ namespace Content.Shared.ActionBlocker return !ev.Cancelled; } - public bool CanEquip(EntityUid uid) - { - var ev = new EquipAttemptEvent(uid); - RaiseLocalEvent(uid, ev); - - return !ev.Cancelled; - } - - public bool CanUnequip(EntityUid uid) - { - var ev = new UnequipAttemptEvent(uid); - RaiseLocalEvent(uid, ev); - - return !ev.Cancelled; - } - public bool CanChangeDirection(EntityUid uid) { var ev = new ChangeDirectionAttemptEvent(uid); diff --git a/Content.Shared/Actions/Components/ItemActionsComponent.cs b/Content.Shared/Actions/Components/ItemActionsComponent.cs index 56bbdbac3c..fbe642a15c 100644 --- a/Content.Shared/Actions/Components/ItemActionsComponent.cs +++ b/Content.Shared/Actions/Components/ItemActionsComponent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Inventory; +using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -23,7 +24,7 @@ namespace Content.Shared.Actions.Components /// Currently only maintained server side and not synced to client, as are all the equip/unequip events. /// [RegisterComponent] - public class ItemActionsComponent : Component, IEquippedHand, IEquipped, IUnequipped, IUnequippedHand + public class ItemActionsComponent : Component, IEquippedHand, IUnequippedHand { public override string Name => "ItemActions"; @@ -34,22 +35,19 @@ namespace Content.Shared.Actions.Components /// public IEnumerable ActionConfigs => _actionConfigs; - public bool IsEquipped => InSlot != EquipmentSlotDefines.Slots.NONE || InHand != null; - /// - /// Slot currently equipped to, NONE if not equipped to an equip slot. - /// - public EquipmentSlotDefines.Slots InSlot { get; private set; } + public bool IsEquipped; + /// /// hand it's currently in, null if not in a hand. /// - public HandState? InHand { get; private set; } + public HandState? InHand; /// /// Entity currently holding this in hand or equip slot. Null if not held. /// - public EntityUid? Holder { get; private set; } + public EntityUid? Holder; // cached actions component of the holder, since we'll need to access it frequently - private SharedActionsComponent? _holderActionsComponent; + public SharedActionsComponent? HolderActionsComponent; [DataField("actions")] private List _actionConfigs @@ -81,21 +79,21 @@ namespace Content.Shared.Actions.Components RevokeAllFromHolder(); } - private void GrantOrUpdateAllToHolder() + public void GrantOrUpdateAllToHolder() { - if (_holderActionsComponent == null) return; + if (HolderActionsComponent == null) return; foreach (var (actionType, state) in _actions) { - _holderActionsComponent.GrantOrUpdateItemAction(actionType, Owner, state); + HolderActionsComponent.GrantOrUpdateItemAction(actionType, Owner, state); } } - private void RevokeAllFromHolder() + public void RevokeAllFromHolder() { - if (_holderActionsComponent == null) return; + if (HolderActionsComponent == null) return; foreach (var (actionType, state) in _actions) { - _holderActionsComponent.RevokeItemAction(actionType, Owner); + HolderActionsComponent.RevokeItemAction(actionType, Owner); } } @@ -152,7 +150,7 @@ namespace Content.Shared.Actions.Components if (!dirty) return; _actions[actionType] = actionState; - _holderActionsComponent?.GrantOrUpdateItemAction(actionType, Owner, actionState); + HolderActionsComponent?.GrantOrUpdateItemAction(actionType, Owner, actionState); } /// @@ -187,40 +185,18 @@ namespace Content.Shared.Actions.Components if (!IoCManager.Resolve().TryGetComponent(eventArgs.User, out var actionsComponent)) return; Holder = eventArgs.User; - _holderActionsComponent = actionsComponent; - InSlot = EquipmentSlotDefines.Slots.NONE; + HolderActionsComponent = actionsComponent; + IsEquipped = true; InHand = eventArgs.Hand; GrantOrUpdateAllToHolder(); } - void IEquipped.Equipped(EquippedEventArgs eventArgs) - { - // this entity cannot be granted actions if no actions component - if (!IoCManager.Resolve().TryGetComponent(eventArgs.User, out var actionsComponent)) - return; - Holder = eventArgs.User; - _holderActionsComponent = actionsComponent; - InSlot = eventArgs.Slot; - InHand = null; - GrantOrUpdateAllToHolder(); - } - - void IUnequipped.Unequipped(UnequippedEventArgs eventArgs) - { - RevokeAllFromHolder(); - Holder = null; - _holderActionsComponent = null; - InSlot = EquipmentSlotDefines.Slots.NONE; - InHand = null; - - } - void IUnequippedHand.UnequippedHand(UnequippedHandEventArgs eventArgs) { RevokeAllFromHolder(); Holder = null; - _holderActionsComponent = null; - InSlot = EquipmentSlotDefines.Slots.NONE; + HolderActionsComponent = null; + IsEquipped = false; InHand = null; } } diff --git a/Content.Shared/Clothing/ClothingComponentState.cs b/Content.Shared/Clothing/ClothingComponentState.cs deleted file mode 100644 index a063fe53e3..0000000000 --- a/Content.Shared/Clothing/ClothingComponentState.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization; - -namespace Content.Shared.Clothing -{ - [Serializable, NetSerializable] - public class ClothingComponentState : ComponentState - { - public string? ClothingEquippedPrefix { get; } - - public string? EquippedPrefix { get; } - - public ClothingComponentState(string? clothingEquippedPrefix, string? equippedPrefix) - { - ClothingEquippedPrefix = clothingEquippedPrefix; - EquippedPrefix = equippedPrefix; - } - } -} diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index d4c42a3355..61c6846e98 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -18,8 +18,8 @@ namespace Content.Shared.Cuffs SubscribeLocalEvent(HandleMoveAttempt); SubscribeLocalEvent(OnUseAttempt); SubscribeLocalEvent(OnInteractAttempt); - SubscribeLocalEvent(OnEquipAttempt); - SubscribeLocalEvent(OnUnequipAttempt); + SubscribeLocalEvent(OnEquipAttempt); + SubscribeLocalEvent(OnUnequipAttempt); SubscribeLocalEvent(OnAttackAttempt); SubscribeLocalEvent(OnDropAttempt); SubscribeLocalEvent(OnPickupAttempt); @@ -61,12 +61,12 @@ namespace Content.Shared.Cuffs CheckAct(uid, component, args); } - private void OnEquipAttempt(EntityUid uid, SharedCuffableComponent component, EquipAttemptEvent args) + private void OnEquipAttempt(EntityUid uid, SharedCuffableComponent component, IsEquippingAttemptEvent args) { CheckAct(uid, component, args); } - private void OnUnequipAttempt(EntityUid uid, SharedCuffableComponent component, UnequipAttemptEvent args) + private void OnUnequipAttempt(EntityUid uid, SharedCuffableComponent component, IsUnequippingAttemptEvent args) { CheckAct(uid, component, args); } diff --git a/Content.Shared/Hands/Components/SharedHandsComponent.cs b/Content.Shared/Hands/Components/SharedHandsComponent.cs index 398aec3203..52c2d1c08a 100644 --- a/Content.Shared/Hands/Components/SharedHandsComponent.cs +++ b/Content.Shared/Hands/Components/SharedHandsComponent.cs @@ -788,15 +788,25 @@ namespace Content.Shared.Hands.Components return TryPutInActiveHandOrAny(item.Owner, checkActionBlocker); } + /// + /// Tries to pick up an entity into the active hand. If it cannot, tries to pick up the entity into each other hand. + /// + public bool PutInHand(EntityUid uid, bool checkActionBlocker = true) + { + return TryPutInActiveHandOrAny(uid, checkActionBlocker); + } + /// /// Puts an item any hand, prefering the active hand, or puts it on the floor under the player. /// - public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true) - { - var entity = item.Owner; + public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true) => + PutInHandOrDrop(item.Owner, checkActionBlocker); + + public void PutInHandOrDrop(EntityUid uid, bool checkActionBlocker = true) + { + if (!TryPutInActiveHandOrAny(uid, checkActionBlocker)) + _entMan.GetComponent(uid).Coordinates = _entMan.GetComponent(Owner).Coordinates; - if (!TryPutInActiveHandOrAny(entity, checkActionBlocker)) - _entMan.GetComponent(entity).Coordinates = _entMan.GetComponent(Owner).Coordinates; } /// diff --git a/Content.Shared/Hands/IEquippedHand.cs b/Content.Shared/Hands/IEquippedHand.cs index fc2a67ae52..d13bd3f815 100644 --- a/Content.Shared/Hands/IEquippedHand.cs +++ b/Content.Shared/Hands/IEquippedHand.cs @@ -20,14 +20,16 @@ namespace Content.Shared.Hands void EquippedHand(EquippedHandEventArgs eventArgs); } - public class EquippedHandEventArgs : UserEventArgs + public class EquippedHandEventArgs : EntityEventArgs { - public EquippedHandEventArgs(EntityUid user, HandState hand) : base(user) + public EquippedHandEventArgs(EntityUid user, HandState hand) { Hand = hand; + User = user; } - public HandState Hand { get; } + public readonly HandState Hand; + public readonly EntityUid User; } /// diff --git a/Content.Shared/Hands/IUnequippedHand.cs b/Content.Shared/Hands/IUnequippedHand.cs index 058d2c4276..89e554fce2 100644 --- a/Content.Shared/Hands/IUnequippedHand.cs +++ b/Content.Shared/Hands/IUnequippedHand.cs @@ -19,14 +19,16 @@ namespace Content.Shared.Hands void UnequippedHand(UnequippedHandEventArgs eventArgs); } - public class UnequippedHandEventArgs : UserEventArgs + public class UnequippedHandEventArgs : EntityEventArgs { - public UnequippedHandEventArgs(EntityUid user, HandState hand) : base(user) + public UnequippedHandEventArgs(EntityUid user, HandState hand) { Hand = hand; + User = user; } - public HandState Hand { get; } + public readonly HandState Hand; + public readonly EntityUid User; } /// diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index a5eb620a4e..540133acc9 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -731,47 +731,6 @@ namespace Content.Shared.Interaction } #endregion - #region Equip - /// - /// Calls Equipped on all components that implement the IEquipped interface - /// on an entity that has been equipped. - /// - public void EquippedInteraction(EntityUid user, EntityUid equipped, EquipmentSlotDefines.Slots slot) - { - var equipMsg = new EquippedEvent(user, equipped, slot); - RaiseLocalEvent(equipped, equipMsg); - if (equipMsg.Handled) - return; - - var comps = AllComps(equipped).ToList(); - - // Call Thrown on all components that implement the interface - foreach (var comp in comps) - { - comp.Equipped(new EquippedEventArgs(user, slot)); - } - } - - /// - /// Calls Unequipped on all components that implement the IUnequipped interface - /// on an entity that has been equipped. - /// - public void UnequippedInteraction(EntityUid user, EntityUid equipped, EquipmentSlotDefines.Slots slot) - { - var unequipMsg = new UnequippedEvent(user, equipped, slot); - RaiseLocalEvent(equipped, unequipMsg); - if (unequipMsg.Handled) - return; - - var comps = AllComps(equipped).ToList(); - - // Call Thrown on all components that implement the interface - foreach (var comp in comps) - { - comp.Unequipped(new UnequippedEventArgs(user, slot)); - } - } - #region Equip Hand /// /// Calls EquippedHand on all components that implement the IEquippedHand interface @@ -811,7 +770,6 @@ namespace Content.Shared.Interaction } } #endregion - #endregion #region Drop /// diff --git a/Content.Shared/Inventory/EquipmentSlotDefinitions.cs b/Content.Shared/Inventory/EquipmentSlotDefinitions.cs deleted file mode 100644 index 7fec296312..0000000000 --- a/Content.Shared/Inventory/EquipmentSlotDefinitions.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; -using Robust.Shared.Serialization; - -namespace Content.Shared.Inventory -{ - public static class EquipmentSlotDefines - { - public static IReadOnlyCollection AllSlots { get; } - - static EquipmentSlotDefines() - { - var output = new Slots[(int)Slots.LAST - (int)Slots.HEAD]; - - // The index stuff is to jump over NONE. - for (var i = 0; i < output.Length; i++) - { - output[i] = (Slots)(i+1); - } - - AllSlots = output; - } - - /// - /// Uniquely identifies a single slot in an inventory. - /// - [Serializable, NetSerializable] - public enum Slots : byte - { - NONE = 0, - HEAD, - EYES, - EARS, - MASK, - OUTERCLOTHING, - INNERCLOTHING, - NECK, - BACKPACK, - BELT, - GLOVES, - SHOES, - IDCARD, - POCKET1, - POCKET2, - - /// - /// Not a real slot. - /// - LAST - } - - /// - /// Defines what slot types an item can fit into. - /// - [Serializable, NetSerializable] - [Flags] - public enum SlotFlags - { - NONE = 0, - PREVENTEQUIP = 1 << 0, - HEAD = 1 << 1, - HELMET = 1 << 1, - EYES = 1 << 2, - EARS = 1 << 3, - MASK = 1 << 4, - OUTERCLOTHING = 1 << 5, - INNERCLOTHING = 1 << 6, - NECK = 1 << 7, - BACK = 1 << 8, - BACKPACK = 1 << 8, - BELT = 1 << 9, - GLOVES = 1 << 10, - HAND = 1 << 10, - IDCARD = 1 << 11, - POCKET = 1 << 12, - LEGS = 1 << 13, - SHOES = 1 << 14, - FEET = 1 << 14, - } - - public static readonly IReadOnlyDictionary SlotNames = new Dictionary() - { - {Slots.HEAD, "Head"}, - {Slots.EYES, "Eyes"}, - {Slots.EARS, "Ears"}, - {Slots.MASK, "Mask"}, - {Slots.OUTERCLOTHING, "Outer Clothing"}, - {Slots.INNERCLOTHING, "Inner Clothing"}, - {Slots.NECK, "Neck"}, - {Slots.BACKPACK, "Backpack"}, - {Slots.BELT, "Belt"}, - {Slots.GLOVES, "Gloves"}, - {Slots.SHOES, "Shoes"}, - {Slots.IDCARD, "Id Card"}, - {Slots.POCKET1, "Left Pocket"}, - {Slots.POCKET2, "Right Pocket"}, - }; - - /// - /// Defines which slot types fit in which slots. - /// - /// - /// Note that this is not exhaustive. Inventory implementations can provide additional behavior. - /// - public static readonly IReadOnlyDictionary SlotMasks = new Dictionary() - { - {Slots.HEAD, SlotFlags.HEAD}, - {Slots.EYES, SlotFlags.EYES}, - {Slots.EARS, SlotFlags.EARS}, - {Slots.MASK, SlotFlags.MASK}, - {Slots.OUTERCLOTHING, SlotFlags.OUTERCLOTHING}, - {Slots.INNERCLOTHING, SlotFlags.INNERCLOTHING}, - {Slots.NECK, SlotFlags.NECK}, - {Slots.BACKPACK, SlotFlags.BACK}, - {Slots.BELT, SlotFlags.BELT}, - {Slots.GLOVES, SlotFlags.GLOVES}, - {Slots.SHOES, SlotFlags.FEET}, - {Slots.IDCARD, SlotFlags.IDCARD}, - {Slots.POCKET1, SlotFlags.POCKET}, - {Slots.POCKET2, SlotFlags.POCKET}, - }; - - // for shared string dict, since we don't define these anywhere in content - [UsedImplicitly] - public static readonly string[] _inventorySlotStrings = - { - "Inventory_HEAD", - "Inventory_EYES", - "Inventory_EARS", - "Inventory_MASK", - "Inventory_OUTERCLOTHING", - "Inventory_INNERCLOTHING", - "Inventory_NECK", - "Inventory_BACKPACK", - "Inventory_BELT", - "Inventory_GLOVES", - "Inventory_SHOES", - "Inventory_IDCARD", - "Inventory_POCKET1", - "Inventory_POCKET2", - }; - - // for shared string dict, since we don't define these anywhere in content - [UsedImplicitly] - public static readonly string[] _handsSlotStrings = - { - "Hands_left", - "Hands_right", - }; - } -} diff --git a/Content.Shared/Inventory/Events/EquipAttemptEvent.cs b/Content.Shared/Inventory/Events/EquipAttemptEvent.cs deleted file mode 100644 index 6f10ce2a90..0000000000 --- a/Content.Shared/Inventory/Events/EquipAttemptEvent.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Robust.Shared.GameObjects; - -namespace Content.Shared.Inventory.Events -{ - public class EquipAttemptEvent : CancellableEntityEventArgs - { - public EquipAttemptEvent(EntityUid uid) - { - Uid = uid; - } - - public EntityUid Uid { get; } - } -} diff --git a/Content.Shared/Inventory/Events/EquipAttemptEvents.cs b/Content.Shared/Inventory/Events/EquipAttemptEvents.cs new file mode 100644 index 0000000000..0c2b4e8062 --- /dev/null +++ b/Content.Shared/Inventory/Events/EquipAttemptEvents.cs @@ -0,0 +1,62 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.Inventory.Events; + +public abstract class EquipAttemptBase : CancellableEntityEventArgs +{ + /// + /// The entity equipping. + /// + public readonly EntityUid Equipee; + + /// + /// The entity being equipped to. + /// + public readonly EntityUid EquipTarget; + + /// + /// The entity to be equipped. + /// + public readonly EntityUid Equipment; + + /// + /// The slotFlags of the slot to equip the entity into. + /// + public readonly SlotFlags SlotFlags; + + /// + /// The slot the entity is being equipped to. + /// + public readonly string Slot; + + /// + /// If cancelling and wanting to provide a custom reason, use this field. Not that this expects a loc-id. + /// + public string? Reason; + + public EquipAttemptBase(EntityUid equipee, EntityUid equipTarget, EntityUid equipment, + SlotDefinition slotDefinition) + { + EquipTarget = equipTarget; + Equipment = equipment; + Equipee = equipee; + SlotFlags = slotDefinition.SlotFlags; + Slot = slotDefinition.Name; + } +} + +public class BeingEquippedAttemptEvent : EquipAttemptBase +{ + public BeingEquippedAttemptEvent(EntityUid equipee, EntityUid equipTarget, EntityUid equipment, + SlotDefinition slotDefinition) : base(equipee, equipTarget, equipment, slotDefinition) + { + } +} + +public class IsEquippingAttemptEvent : EquipAttemptBase +{ + public IsEquippingAttemptEvent(EntityUid equipee, EntityUid equipTarget, EntityUid equipment, + SlotDefinition slotDefinition) : base(equipee, equipTarget, equipment, slotDefinition) + { + } +} diff --git a/Content.Shared/Inventory/Events/EquippedEvents.cs b/Content.Shared/Inventory/Events/EquippedEvents.cs new file mode 100644 index 0000000000..ce447cc473 --- /dev/null +++ b/Content.Shared/Inventory/Events/EquippedEvents.cs @@ -0,0 +1,48 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.Inventory.Events; + +public class EquippedEventBase : EntityEventArgs +{ + /// + /// The entity equipping. + /// + public readonly EntityUid Equipee; + + /// + /// The entity which got equipped. + /// + public readonly EntityUid Equipment; + + /// + /// The slot the entity got equipped to. + /// + public readonly string Slot; + + /// + /// Slotflags of the slot the entity just got equipped to. + /// + public readonly SlotFlags SlotFlags; + + public EquippedEventBase(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) + { + Equipee = equipee; + Equipment = equipment; + Slot = slotDefinition.Name; + SlotFlags = slotDefinition.SlotFlags; + } +} + +public class DidEquipEvent : EquippedEventBase +{ + public DidEquipEvent(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) : base(equipee, equipment, slotDefinition) + { + } +} + +public class GotEquippedEvent : EquippedEventBase +{ + public GotEquippedEvent(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) : base(equipee, equipment, slotDefinition) + { + } +} diff --git a/Content.Shared/Inventory/Events/InventoryEquipActEvent.cs b/Content.Shared/Inventory/Events/InventoryEquipActEvent.cs new file mode 100644 index 0000000000..a174bedc49 --- /dev/null +++ b/Content.Shared/Inventory/Events/InventoryEquipActEvent.cs @@ -0,0 +1,27 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Inventory.Events; + +/// +/// This event is used to tell the server-inventorysystem someone wants to equip something +/// +[NetSerializable, Serializable] +public class InventoryEquipActEvent : EntityEventArgs +{ + public readonly EntityUid Uid; + public readonly EntityUid ItemUid; + public readonly string Slot; + public readonly bool Silent; + public readonly bool Force; + + public InventoryEquipActEvent(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false) + { + Uid = uid; + ItemUid = itemUid; + Slot = slot; + Silent = silent; + Force = force; + } +} diff --git a/Content.Shared/Inventory/Events/OpenSlotStorageNetworkMessage.cs b/Content.Shared/Inventory/Events/OpenSlotStorageNetworkMessage.cs new file mode 100644 index 0000000000..006336b101 --- /dev/null +++ b/Content.Shared/Inventory/Events/OpenSlotStorageNetworkMessage.cs @@ -0,0 +1,18 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Inventory.Events; + +[NetSerializable, Serializable] +public class OpenSlotStorageNetworkMessage : EntityEventArgs +{ + public readonly EntityUid Uid; + public readonly string Slot; + + public OpenSlotStorageNetworkMessage(EntityUid uid, string slot) + { + Uid = uid; + Slot = slot; + } +} diff --git a/Content.Shared/Inventory/Events/TryEquipNetworkMessage.cs b/Content.Shared/Inventory/Events/TryEquipNetworkMessage.cs new file mode 100644 index 0000000000..83df152213 --- /dev/null +++ b/Content.Shared/Inventory/Events/TryEquipNetworkMessage.cs @@ -0,0 +1,26 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Inventory.Events; + +[NetSerializable, Serializable] +public class TryEquipNetworkMessage : EntityEventArgs +{ + public readonly EntityUid Actor; + public readonly EntityUid Target; + public readonly EntityUid ItemUid; + public readonly string Slot; + public readonly bool Silent; + public readonly bool Force; + + public TryEquipNetworkMessage(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent, bool force) + { + Actor = actor; + Target = target; + ItemUid = itemUid; + Slot = slot; + Silent = silent; + Force = force; + } +} diff --git a/Content.Shared/Inventory/Events/TryUnequipNetworkMessage.cs b/Content.Shared/Inventory/Events/TryUnequipNetworkMessage.cs new file mode 100644 index 0000000000..3933c8162e --- /dev/null +++ b/Content.Shared/Inventory/Events/TryUnequipNetworkMessage.cs @@ -0,0 +1,24 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Inventory.Events; + +[NetSerializable, Serializable] +public class TryUnequipNetworkMessage : EntityEventArgs +{ + public readonly EntityUid Actor; + public readonly EntityUid Target; + public readonly string Slot; + public readonly bool Silent; + public readonly bool Force; + + public TryUnequipNetworkMessage(EntityUid actor, EntityUid target, string slot, bool silent, bool force) + { + Actor = actor; + Target = target; + Slot = slot; + Silent = silent; + Force = force; + } +} diff --git a/Content.Shared/Inventory/Events/UnequipAttemptEvent.cs b/Content.Shared/Inventory/Events/UnequipAttemptEvent.cs index 05cd32a4dc..5fbe120364 100644 --- a/Content.Shared/Inventory/Events/UnequipAttemptEvent.cs +++ b/Content.Shared/Inventory/Events/UnequipAttemptEvent.cs @@ -1,14 +1,56 @@ using Robust.Shared.GameObjects; -namespace Content.Shared.Inventory.Events -{ - public class UnequipAttemptEvent : CancellableEntityEventArgs - { - public UnequipAttemptEvent(EntityUid uid) - { - Uid = uid; - } +namespace Content.Shared.Inventory.Events; - public EntityUid Uid { get; } +public class UnequipAttemptEventBase : CancellableEntityEventArgs +{ + /// + /// The entity unequipping. + /// + public readonly EntityUid Unequipee; + + /// + /// The entity being unequipped from. + /// + public readonly EntityUid UnEquipTarget; + + /// + /// The entity to be unequipped. + /// + public readonly EntityUid Equipment; + + /// + /// The slot the entity is being unequipped from. + /// + public readonly string Slot; + + /// + /// If cancelling and wanting to provide a custom reason, use this field. Not that this expects a loc-id. + /// + public string? Reason; + + public UnequipAttemptEventBase(EntityUid unequipee, EntityUid unEquipTarget, EntityUid equipment, + SlotDefinition slotDefinition) + { + UnEquipTarget = unEquipTarget; + Equipment = equipment; + Unequipee = unequipee; + Slot = slotDefinition.Name; + } +} + +public class BeingUnequippedAttemptEvent : UnequipAttemptEventBase +{ + public BeingUnequippedAttemptEvent(EntityUid unequipee, EntityUid unEquipTarget, EntityUid equipment, + SlotDefinition slotDefinition) : base(unequipee, unEquipTarget, equipment, slotDefinition) + { + } +} + +public class IsUnequippingAttemptEvent : UnequipAttemptEventBase +{ + public IsUnequippingAttemptEvent(EntityUid unequipee, EntityUid unEquipTarget, EntityUid equipment, + SlotDefinition slotDefinition) : base(unequipee, unEquipTarget, equipment, slotDefinition) + { } } diff --git a/Content.Shared/Inventory/Events/UnequippedEvents.cs b/Content.Shared/Inventory/Events/UnequippedEvents.cs new file mode 100644 index 0000000000..3522abfb6d --- /dev/null +++ b/Content.Shared/Inventory/Events/UnequippedEvents.cs @@ -0,0 +1,42 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.Inventory.Events; + +public class UnequippedEventBase : EntityEventArgs +{ + /// + /// The entity unequipping. + /// + public readonly EntityUid Equipee; + + /// + /// The entity which got unequipped. + /// + public readonly EntityUid Equipment; + + /// + /// The slot the entity got unequipped from. + /// + public readonly string Slot; + + public UnequippedEventBase(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) + { + Equipee = equipee; + Equipment = equipment; + Slot = slotDefinition.Name; + } +} + +public class DidUnequipEvent : UnequippedEventBase +{ + public DidUnequipEvent(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) : base(equipee, equipment, slotDefinition) + { + } +} + +public class GotUnequippedEvent : UnequippedEventBase +{ + public GotUnequippedEvent(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) : base(equipee, equipment, slotDefinition) + { + } +} diff --git a/Content.Shared/Inventory/Events/UseSlotNetworkMessage.cs b/Content.Shared/Inventory/Events/UseSlotNetworkMessage.cs new file mode 100644 index 0000000000..e563896433 --- /dev/null +++ b/Content.Shared/Inventory/Events/UseSlotNetworkMessage.cs @@ -0,0 +1,18 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Inventory.Events; + +[NetSerializable, Serializable] +public class UseSlotNetworkMessage : EntityEventArgs +{ + public readonly EntityUid Uid; + public readonly string Slot; + + public UseSlotNetworkMessage(EntityUid uid, string slot) + { + Uid = uid; + Slot = slot; + } +} diff --git a/Content.Shared/Inventory/IEquipped.cs b/Content.Shared/Inventory/IEquipped.cs deleted file mode 100644 index b8e3bad7f7..0000000000 --- a/Content.Shared/Inventory/IEquipped.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using Content.Shared.Hands; -using JetBrains.Annotations; -using Robust.Shared.Analyzers; -using Robust.Shared.GameObjects; - -namespace Content.Shared.Inventory -{ - /// - /// This interface gives components behavior when their entity is put in a non-hand inventory slot, - /// regardless of where it came from. This includes moving the entity from a hand slot into a non-hand slot - /// (which would also fire ). - /// - /// This DOES NOT fire when putting the entity into a hand slot (), nor - /// does it fire when putting the entity into held/equipped storage. - /// - [RequiresExplicitImplementation] - public interface IEquipped - { - [Obsolete("Use EquippedMessage instead")] - void Equipped(EquippedEventArgs eventArgs); - } - - public abstract class UserEventArgs : EventArgs - { - public EntityUid User { get; } - - protected UserEventArgs(EntityUid user) - { - User = user; - } - } - - public class EquippedEventArgs : UserEventArgs - { - public EquippedEventArgs(EntityUid user, EquipmentSlotDefines.Slots slot) : base(user) - { - Slot = slot; - } - - public EquipmentSlotDefines.Slots Slot { get; } - } - - /// - /// Raised when equipping an entity in an inventory slot. - /// - [PublicAPI] - public class EquippedEvent : HandledEntityEventArgs - { - /// - /// Entity that equipped the item. - /// - public EntityUid User { get; } - - /// - /// Item that was equipped. - /// - public EntityUid Equipped { get; } - - /// - /// Slot that the item was placed into. - /// - public EquipmentSlotDefines.Slots Slot { get; } - - public EquippedEvent(EntityUid user, EntityUid equipped, EquipmentSlotDefines.Slots slot) - { - User = user; - Equipped = equipped; - Slot = slot; - } - } -} diff --git a/Content.Shared/Inventory/IUnequipped.cs b/Content.Shared/Inventory/IUnequipped.cs deleted file mode 100644 index 5981ca1dd2..0000000000 --- a/Content.Shared/Inventory/IUnequipped.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using Content.Shared.Hands; -using JetBrains.Annotations; -using Robust.Shared.Analyzers; -using Robust.Shared.GameObjects; - -namespace Content.Shared.Inventory -{ - /// - /// This interface gives components behavior when their entity is removed from a non-hand inventory slot, - /// regardless of where it's going to. This includes moving the entity from a non-hand slot into a hand slot - /// (which would also fire ). - /// - /// This DOES NOT fire when removing the entity from a hand slot (), nor - /// does it fire when removing the entity from held/equipped storage. - /// - [RequiresExplicitImplementation] - public interface IUnequipped - { - [Obsolete("Use UnequippedMessage instead")] - void Unequipped(UnequippedEventArgs eventArgs); - } - - public class UnequippedEventArgs : UserEventArgs - { - public UnequippedEventArgs(EntityUid user, EquipmentSlotDefines.Slots slot) : base(user) - { - Slot = slot; - } - - public EquipmentSlotDefines.Slots Slot { get; } - } - - /// - /// Raised when removing an entity from an inventory slot. - /// - [PublicAPI] - public class UnequippedEvent : HandledEntityEventArgs - { - /// - /// Entity that equipped the item. - /// - public EntityUid User { get; } - - /// - /// Item that was unequipped. - /// - public EntityUid Unequipped { get; } - - /// - /// Slot that the item was removed from. - /// - public EquipmentSlotDefines.Slots Slot { get; } - - public UnequippedEvent(EntityUid user, EntityUid unequipped, EquipmentSlotDefines.Slots slot) - { - User = user; - Unequipped = unequipped; - Slot = slot; - } - } - - -} diff --git a/Content.Shared/Inventory/InventoryComponent.cs b/Content.Shared/Inventory/InventoryComponent.cs new file mode 100644 index 0000000000..1619e05bd6 --- /dev/null +++ b/Content.Shared/Inventory/InventoryComponent.cs @@ -0,0 +1,40 @@ +using System.Linq; +using Content.Shared.Acts; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Inventory; + +public class InventoryComponent : Component, IExAct +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + + public sealed override string Name => "Inventory"; + + [DataField("templateId", required: true, + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string TemplateId { get; } = "human"; + + void IExAct.OnExplosion(ExplosionEventArgs eventArgs) + { + if (eventArgs.Severity < ExplosionSeverity.Heavy) + { + return; + } + + if (EntitySystem.Get() + .TryGetContainerSlotEnumerator(Owner, out var enumerator, this)) + { + while (enumerator.MoveNext(out var container)) + { + if (!container.ContainedEntity.HasValue) continue; + foreach (var exAct in _entityManager.GetComponents(container.ContainedEntity.Value).ToArray()) + { + exAct.OnExplosion(eventArgs); + } + } + } + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs new file mode 100644 index 0000000000..3a5dd5346c --- /dev/null +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -0,0 +1,293 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Hands.Components; +using Content.Shared.Inventory.Events; +using Content.Shared.Item; +using Content.Shared.Movement.EntitySystems; +using Content.Shared.Popups; +using Robust.Shared.Audio; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Player; + +namespace Content.Shared.Inventory; + +public abstract partial class InventorySystem +{ + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; + + private void InitializeEquip() + { + //these events ensure that the client also gets its proper events raised when getting its containerstate updated + SubscribeLocalEvent(OnEntInserted); + SubscribeLocalEvent(OnEntRemoved); + } + + private void OnEntRemoved(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args) + { + if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component)) + return; + + var unequippedEvent = new DidUnequipEvent(uid, args.Entity, slotDef); + RaiseLocalEvent(uid, unequippedEvent); + + var gotUnequippedEvent = new GotUnequippedEvent(uid, args.Entity, slotDef); + RaiseLocalEvent(args.Entity, gotUnequippedEvent); + } + + private void OnEntInserted(EntityUid uid, InventoryComponent component, EntInsertedIntoContainerMessage args) + { + if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component)) + return; + + var equippedEvent = new DidEquipEvent(uid, args.Entity, slotDef); + RaiseLocalEvent(uid, equippedEvent); + + var gotEquippedEvent = new GotEquippedEvent(uid, args.Entity, slotDef); + RaiseLocalEvent(args.Entity, gotEquippedEvent); + } + + public bool TryEquipActiveHandTo(EntityUid uid, string slot, bool silent = false, bool force = false, + InventoryComponent? component = null, SharedHandsComponent? hands = null) + { + if (!Resolve(uid, ref component, false) || !Resolve(uid, ref hands, false)) + return false; + + if (!hands.TryGetActiveHeldEntity(out var heldEntity)) + return false; + + return TryEquip(uid, heldEntity, slot, silent, force, component); + } + + public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, + InventoryComponent? inventory = null, SharedItemComponent? item = null) => + TryEquip(uid, uid, itemUid, slot, silent, force, inventory, item); + + public virtual bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false, InventoryComponent? inventory = null, SharedItemComponent? item = null) + { + if (!Resolve(target, ref inventory, false) || !Resolve(itemUid, ref item, false)) + { + if(!silent) _popup.PopupCursor(Loc.GetString("inventory-component-can-equip-cannot"), Filter.Local()); + return false; + } + + if (!TryGetSlotContainer(target, slot, out var slotContainer, out var slotDefinition, inventory)) + { + if(!silent) _popup.PopupCursor(Loc.GetString("inventory-component-can-equip-cannot"), Filter.Local()); + return false; + } + + if (!force && !CanEquip(actor, target, itemUid, slot, out var reason, slotDefinition, inventory, item)) + { + if(!silent) _popup.PopupCursor(Loc.GetString(reason), Filter.Local()); + return false; + } + + if (!slotContainer.Insert(itemUid)) + { + if(!silent) _popup.PopupCursor(Loc.GetString("inventory-component-can-unequip-cannot"), Filter.Local()); + return false; + } + + if(item.EquipSound != null) + SoundSystem.Play(Filter.Pvs(target), item.EquipSound.GetSound(), target, AudioParams.Default.WithVolume(-2f)); + + inventory.Dirty(); + + _movementSpeed.RefreshMovementSpeedModifiers(target); + + return true; + } + + public bool CanEquip(EntityUid uid, EntityUid itemUid, string slot, [NotNullWhen(false)] out string? reason, + SlotDefinition? slotDefinition = null, InventoryComponent? inventory = null, + SharedItemComponent? item = null) => + CanEquip(uid, uid, itemUid, slot, out reason, slotDefinition, inventory, item); + + public bool CanEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, [NotNullWhen(false)] out string? reason, SlotDefinition? slotDefinition = null, InventoryComponent? inventory = null, SharedItemComponent? item = null) + { + reason = "inventory-component-can-equip-cannot"; + if (!Resolve(target, ref inventory, false) || !Resolve(itemUid, ref item, false)) + return false; + + if (slotDefinition == null && !TryGetSlot(target, slot, out slotDefinition, inventory: inventory)) + return false; + + if (slotDefinition.DependsOn != null && !TryGetSlotEntity(target, slotDefinition.DependsOn, out _, inventory)) + return false; + + if(!item.SlotFlags.HasFlag(slotDefinition.SlotFlags) && (!slotDefinition.SlotFlags.HasFlag(SlotFlags.POCKET) || item.Size > (int) ReferenceSizes.Pocket)) + { + reason = "inventory-component-can-equip-does-not-fit"; + return false; + } + + var attemptEvent = new IsEquippingAttemptEvent(actor, target, itemUid, slotDefinition); + RaiseLocalEvent(target, attemptEvent); + if (attemptEvent.Cancelled) + { + reason = attemptEvent.Reason ?? reason; + return false; + } + + if (actor != target) + { + //reuse the event. this is gucci, right? + attemptEvent.Reason = null; + RaiseLocalEvent(actor, attemptEvent); + if (attemptEvent.Cancelled) + { + reason = attemptEvent.Reason ?? reason; + return false; + } + } + + var itemAttemptEvent = new BeingEquippedAttemptEvent(actor, target, itemUid, slotDefinition); + RaiseLocalEvent(itemUid, itemAttemptEvent); + if (itemAttemptEvent.Cancelled) + { + reason = itemAttemptEvent.Reason ?? reason; + return false; + } + + return true; + } + + public bool TryUnequip(EntityUid uid, string slot, bool silent = false, bool force = false, + InventoryComponent? inventory = null) => TryUnequip(uid, uid, slot, silent, force, inventory); + + public bool TryUnequip(EntityUid actor, EntityUid target, string slot, bool silent = false, + bool force = false, InventoryComponent? inventory = null) => + TryUnequip(actor, target, slot, out _, silent, force, inventory); + + public bool TryUnequip(EntityUid uid, string slot, [NotNullWhen(true)] out EntityUid? removedItem, bool silent = false, bool force = false, + InventoryComponent? inventory = null) => TryUnequip(uid, uid, slot, out removedItem, silent, force, inventory); + + public virtual bool TryUnequip(EntityUid actor, EntityUid target, string slot, [NotNullWhen(true)] out EntityUid? removedItem, bool silent = false, + bool force = false, InventoryComponent? inventory = null) + { + removedItem = null; + if (!Resolve(target, ref inventory, false)) + { + if(!silent) _popup.PopupCursor(Loc.GetString("inventory-component-can-unequip-cannot"), Filter.Local()); + return false; + } + + if (!TryGetSlotContainer(target, slot, out var slotContainer, out var slotDefinition, inventory)) + { + if(!silent) _popup.PopupCursor(Loc.GetString("inventory-component-can-unequip-cannot"), Filter.Local()); + return false; + } + + removedItem = slotContainer.ContainedEntity; + + if (!removedItem.HasValue) return false; + + if (!force && !CanUnequip(actor, target, slot, out var reason, slotContainer, slotDefinition, inventory)) + { + if(!silent) _popup.PopupCursor(Loc.GetString(reason), Filter.Local()); + return false; + } + + //we need to do this to make sure we are 100% removing this entity, since we are now dropping dependant slots + if (!force && !slotContainer.CanRemove(removedItem.Value)) + return false; + + foreach (var slotDef in GetSlots(target, inventory)) + { + if (slotDef != slotDefinition && slotDef.DependsOn == slotDefinition.Name) + { + //this recursive call might be risky + TryUnequip(actor, target, slotDef.Name, true, true, inventory); + } + } + + if (force) + { + slotContainer.ForceRemove(removedItem.Value); + } + else + { + if (!slotContainer.Remove(removedItem.Value)) + { + //should never happen bc of the canremove lets just keep in just in case + return false; + } + } + + Transform(removedItem.Value).Coordinates = Transform(target).Coordinates; + + inventory.Dirty(); + + _movementSpeed.RefreshMovementSpeedModifiers(target); + + return true; + } + + public bool CanUnequip(EntityUid uid, string slot, [NotNullWhen(false)] out string? reason, + ContainerSlot? containerSlot = null, SlotDefinition? slotDefinition = null, + InventoryComponent? inventory = null) => + CanUnequip(uid, uid, slot, out reason, containerSlot, slotDefinition, inventory); + + public bool CanUnequip(EntityUid actor, EntityUid target, string slot, [NotNullWhen(false)] out string? reason, ContainerSlot? containerSlot = null, SlotDefinition? slotDefinition = null, InventoryComponent? inventory = null) + { + reason = "inventory-component-can-unequip-cannot"; + if (!Resolve(target, ref inventory, false)) + return false; + + if ((containerSlot == null || slotDefinition == null) && !TryGetSlotContainer(target, slot, out containerSlot, out slotDefinition, inventory)) + return false; + + if (containerSlot.ContainedEntity == null) + return false; + + if (!containerSlot.ContainedEntity.HasValue || !containerSlot.CanRemove(containerSlot.ContainedEntity.Value)) + return false; + + var itemUid = containerSlot.ContainedEntity.Value; + + var attemptEvent = new IsUnequippingAttemptEvent(actor, target, itemUid, slotDefinition); + RaiseLocalEvent(target, attemptEvent); + if (attemptEvent.Cancelled) + { + reason = attemptEvent.Reason ?? reason; + return false; + } + + if (actor != target) + { + //reuse the event. this is gucci, right? + attemptEvent.Reason = null; + RaiseLocalEvent(actor, attemptEvent); + if (attemptEvent.Cancelled) + { + reason = attemptEvent.Reason ?? reason; + return false; + } + } + + var itemAttemptEvent = new BeingUnequippedAttemptEvent(actor, target, itemUid, slotDefinition); + RaiseLocalEvent(itemUid, itemAttemptEvent); + if (itemAttemptEvent.Cancelled) + { + reason = attemptEvent.Reason ?? reason; + return false; + } + + return true; + } + + public bool TryGetSlotEntity(EntityUid uid, string slot, [NotNullWhen(true)] out EntityUid? entityUid, InventoryComponent? inventoryComponent = null, ContainerManagerComponent? containerManagerComponent = null) + { + entityUid = null; + if (!Resolve(uid, ref inventoryComponent, ref containerManagerComponent, false) + || !TryGetSlotContainer(uid, slot, out var container, out _, inventoryComponent, containerManagerComponent)) + return false; + + entityUid = container.ContainedEntity; + return entityUid != null; + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Helpers.cs b/Content.Shared/Inventory/InventorySystem.Helpers.cs new file mode 100644 index 0000000000..f74f984327 --- /dev/null +++ b/Content.Shared/Inventory/InventorySystem.Helpers.cs @@ -0,0 +1,43 @@ +using Content.Shared.Item; +using Robust.Shared.GameObjects; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Inventory; + +public partial class InventorySystem +{ + public bool SpawnItemInSlot(EntityUid uid, string slot, string prototype, bool silent = false, bool force = false, InventoryComponent? inventory = null) + { + if (!Resolve(uid, ref inventory, false)) + return false; + + // Let's do nothing if the owner of the inventory has been deleted. + if (Deleted(uid)) + return false; + + // If we don't have that slot or there's already an item there, we do nothing. + if (!HasSlot(uid, slot) || TryGetSlotEntity(uid, slot, out _, inventory)) + return false; + + // If the prototype in question doesn't exist, we do nothing. + if (!_prototypeManager.HasIndex(prototype)) + return false; + + // Let's spawn this first... + var item = EntityManager.SpawnEntity(prototype, Transform(uid).Coordinates); + + // Helper method that deletes the item and returns false. + bool DeleteItem() + { + EntityManager.DeleteEntity(item); + return false; + } + + // If this doesn't have an item component, then we can't do anything with it. + if (!HasComp(item)) + return DeleteItem(); + + // We finally try to equip the item, otherwise we delete it. + return TryEquip(uid, item, slot, silent, force) || DeleteItem(); + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs new file mode 100644 index 0000000000..5be3240681 --- /dev/null +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -0,0 +1,28 @@ +using Content.Shared.Damage; +using Content.Shared.Electrocution; +using Content.Shared.Movement.EntitySystems; +using Content.Shared.Slippery; +using Robust.Shared.GameObjects; + +namespace Content.Shared.Inventory; + +public partial class InventorySystem +{ + public void InitializeRelay() + { + SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); + } + + protected void RelayInventoryEvent(EntityUid uid, InventoryComponent component, T args) where T : EntityEventArgs + { + var containerEnumerator = new ContainerSlotEnumerator(uid, component.TemplateId, _prototypeManager, this); + while(containerEnumerator.MoveNext(out var container)) + { + if(!container.ContainedEntity.HasValue) continue; + RaiseLocalEvent(container.ContainedEntity.Value, args, false); + } + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Slots.cs b/Content.Shared/Inventory/InventorySystem.Slots.cs new file mode 100644 index 0000000000..625b8a2eee --- /dev/null +++ b/Content.Shared/Inventory/InventorySystem.Slots.cs @@ -0,0 +1,116 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Inventory; + +public partial class InventorySystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public bool TryGetSlotContainer(EntityUid uid, string slot, [NotNullWhen(true)] out ContainerSlot? containerSlot, [NotNullWhen(true)] out SlotDefinition? slotDefinition, + InventoryComponent? inventory = null, ContainerManagerComponent? containerComp = null) + { + containerSlot = null; + slotDefinition = null; + if (!Resolve(uid, ref inventory, ref containerComp, false)) + return false; + + if (!TryGetSlot(uid, slot, out slotDefinition, inventory: inventory)) + return false; + + if (!containerComp.TryGetContainer(slotDefinition.Name, out var container)) + { + containerSlot = containerComp.MakeContainer(slotDefinition.Name); + return true; + } + + if (container is not ContainerSlot containerSlotChecked) return false; + + containerSlot = containerSlotChecked; + return true; + } + + public bool HasSlot(EntityUid uid, string slot, InventoryComponent? component = null) => + TryGetSlot(uid, slot, out _, component); + + public bool TryGetSlot(EntityUid uid, string slot, [NotNullWhen(true)] out SlotDefinition? slotDefinition, InventoryComponent? inventory = null) + { + slotDefinition = null; + if (!Resolve(uid, ref inventory, false)) + return false; + + if (!_prototypeManager.TryIndex(inventory.TemplateId, out var templatePrototype)) + return false; + + slotDefinition = templatePrototype.Slots.FirstOrDefault(x => x.Name == slot); + return slotDefinition != default; + } + + public bool TryGetContainerSlotEnumerator(EntityUid uid, out ContainerSlotEnumerator containerSlotEnumerator, InventoryComponent? component = null) + { + containerSlotEnumerator = default; + if (!Resolve(uid, ref component, false)) + return false; + + containerSlotEnumerator = new ContainerSlotEnumerator(uid, component.TemplateId, _prototypeManager, this); + return true; + } + + public bool TryGetSlots(EntityUid uid, [NotNullWhen(true)] out SlotDefinition[]? slotDefinitions, InventoryComponent? inventoryComponent = null) + { + slotDefinitions = null; + if (!Resolve(uid, ref inventoryComponent, false)) + return false; + + if (!_prototypeManager.TryIndex(inventoryComponent.TemplateId, out var templatePrototype)) + return false; + + slotDefinitions = templatePrototype.Slots; + return true; + } + + public SlotDefinition[] GetSlots(EntityUid uid, InventoryComponent? inventoryComponent = null) + { + if (!Resolve(uid, ref inventoryComponent)) throw new InvalidOperationException(); + return _prototypeManager.Index(inventoryComponent.TemplateId).Slots; + } + + public struct ContainerSlotEnumerator + { + private readonly InventorySystem _inventorySystem; + private readonly EntityUid _uid; + private readonly SlotDefinition[] _slots; + private int _nextIdx = int.MaxValue; + + public ContainerSlotEnumerator(EntityUid uid, string prototypeId, IPrototypeManager prototypeManager, InventorySystem inventorySystem) + { + _uid = uid; + _inventorySystem = inventorySystem; + if (prototypeManager.TryIndex(prototypeId, out var prototype)) + { + _slots = prototype.Slots; + if(_slots.Length > 0) + _nextIdx = 0; + } + else + { + _slots = Array.Empty(); + } + } + + public bool MoveNext([NotNullWhen(true)] out ContainerSlot? container) + { + container = null; + if (_nextIdx >= _slots.Length) return false; + + while (_nextIdx < _slots.Length && !_inventorySystem.TryGetSlotContainer(_uid, _slots[_nextIdx++].Name, out container, out _)) { } + + return container != null; + } + } +} diff --git a/Content.Shared/Inventory/InventorySystem.cs b/Content.Shared/Inventory/InventorySystem.cs new file mode 100644 index 0000000000..5b8a6585aa --- /dev/null +++ b/Content.Shared/Inventory/InventorySystem.cs @@ -0,0 +1,14 @@ +using Content.Shared.Inventory.Events; + +namespace Content.Shared.Inventory; + +public partial class InventorySystem +{ + + public override void Initialize() + { + base.Initialize(); + InitializeEquip(); + InitializeRelay(); + } +} diff --git a/Content.Shared/Inventory/InventoryTemplatePrototype.cs b/Content.Shared/Inventory/InventoryTemplatePrototype.cs new file mode 100644 index 0000000000..d98c212239 --- /dev/null +++ b/Content.Shared/Inventory/InventoryTemplatePrototype.cs @@ -0,0 +1,45 @@ +using System; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Utility; + +namespace Content.Shared.Inventory; + +[Prototype("inventoryTemplate")] +public class InventoryTemplatePrototype : IPrototype +{ + [DataField("id", required: true)] + public string ID { get; } = string.Empty; + + [DataField("slots")] + public SlotDefinition[] Slots { get; } = Array.Empty(); +} + +[DataDefinition] +public class SlotDefinition +{ + [DataField("name", required: true)] public string Name { get; } = string.Empty; + + [DataField("slotTexture")] public string TextureName { get; } = "pocket"; + + [DataField("slotFlags")] public SlotFlags SlotFlags { get; } = SlotFlags.PREVENTEQUIP; + + [DataField("uiContainer")] public SlotUIContainer UIContainer { get; } = SlotUIContainer.None; + + [DataField("uiWindowPos", required: true)] public Vector2i UIWindowPosition { get; } + + //todo this is supreme shit and ideally slots should be stored in a given equipmentslotscomponent on each equipment + [DataField("dependsOn")] public string? DependsOn { get; } + + [DataField("displayName", required: true)] public string DisplayName { get; } = string.Empty; +} + +public enum SlotUIContainer +{ + None, + BottomLeft, + BottomRight, + Top +} diff --git a/Content.Shared/Inventory/InventoryTemplates.cs b/Content.Shared/Inventory/InventoryTemplates.cs deleted file mode 100644 index 56c8d98ad9..0000000000 --- a/Content.Shared/Inventory/InventoryTemplates.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using JetBrains.Annotations; -using static Content.Shared.Inventory.EquipmentSlotDefines; - -namespace Content.Shared.Inventory -{ - public abstract class Inventory - { - public abstract string InterfaceControllerTypeName { get; } - - public abstract IReadOnlyList SlotMasks { get; } - - /// - /// Gets the drawing order of a slot. - /// - /// - /// An int that can be used for sorting relative to other drawing orders. - /// The value returned does not mean anything else. - /// - public abstract int SlotDrawingOrder(Slots slot); - } - - // Dynamically created by SharedInventoryComponent. - [UsedImplicitly] - public class HumanInventory : Inventory - { - public override string InterfaceControllerTypeName => "HumanInventoryInterfaceController"; - - private static readonly Dictionary _slotDrawingOrder = new() - { - {Slots.POCKET1, 13}, - {Slots.POCKET2, 12}, - {Slots.HEAD, 11}, - {Slots.MASK, 10}, - {Slots.EARS, 9}, - {Slots.NECK, 8}, - {Slots.BACKPACK, 7}, - {Slots.EYES, 6}, - {Slots.OUTERCLOTHING, 5}, - {Slots.BELT, 4}, - {Slots.GLOVES, 3}, - {Slots.SHOES, 2}, - {Slots.IDCARD, 1}, - {Slots.INNERCLOTHING, 0} - }; - - public override IReadOnlyList SlotMasks { get; } = new List() - { - 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.POCKET1, Slots.POCKET2, - Slots.NECK - }; - - public override int SlotDrawingOrder(Slots slot) - { - return _slotDrawingOrder.TryGetValue(slot, out var val) ? val : 0; - } - } -} diff --git a/Content.Shared/Inventory/SharedInventoryComponent.cs b/Content.Shared/Inventory/SharedInventoryComponent.cs deleted file mode 100644 index 8e7e73e531..0000000000 --- a/Content.Shared/Inventory/SharedInventoryComponent.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using Robust.Shared.GameObjects; -using Robust.Shared.GameStates; -using Robust.Shared.IoC; -using Robust.Shared.Reflection; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.Utility; -using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; - -namespace Content.Shared.Inventory -{ - [NetworkedComponent()] - public abstract class SharedInventoryComponent : Component - { - [Dependency] protected readonly IReflectionManager ReflectionManager = default!; - [Dependency] protected readonly IDynamicTypeFactory DynamicTypeFactory = default!; - - public sealed override string Name => "Inventory"; - - [ViewVariables] - protected Inventory InventoryInstance { get; private set; } = default!; - - [ViewVariables] - [DataField("Template")] - private string _templateName = "HumanInventory"; //stored for serialization purposes - - protected override void Initialize() - { - base.Initialize(); - - CreateInventory(); - } - - private void CreateInventory() - { - var type = ReflectionManager.LooseGetType(_templateName); - DebugTools.Assert(type != null); - InventoryInstance = DynamicTypeFactory.CreateInstance(type!); - } - - public abstract bool TryGetSlot(Slots slot, [NotNullWhen(true)] out EntityUid? item); - - /// true if the item is equipped to an equip slot (NOT inside an equipped container - /// like inside a backpack) - public abstract bool IsEquipped(EntityUid item); - - [Serializable, NetSerializable] - protected class InventoryComponentState : ComponentState - { - public List> Entities { get; } - public KeyValuePair? HoverEntity { get; } - - public InventoryComponentState(List> entities, KeyValuePair? hoverEntity = null) - { - Entities = entities; - HoverEntity = hoverEntity; - } - } - - [Serializable, NetSerializable] -#pragma warning disable 618 - public class ClientInventoryMessage : ComponentMessage -#pragma warning restore 618 - { - public Slots Inventoryslot; - public ClientInventoryUpdate Updatetype; - - public ClientInventoryMessage(Slots inventoryslot, ClientInventoryUpdate updatetype) - { - Directed = true; - Inventoryslot = inventoryslot; - Updatetype = updatetype; - } - - public enum ClientInventoryUpdate - { - Equip = 0, - Use = 1, - Hover = 2 - } - } - - /// - /// Component message for opening the Storage UI of item in Slot - /// - [Serializable, NetSerializable] -#pragma warning disable 618 - public class OpenSlotStorageUIMessage : ComponentMessage -#pragma warning restore 618 - { - public Slots Slot; - - public OpenSlotStorageUIMessage(Slots slot) - { - Directed = true; - Slot = slot; - } - } - } -} diff --git a/Content.Shared/Inventory/SlotFlags.cs b/Content.Shared/Inventory/SlotFlags.cs new file mode 100644 index 0000000000..9031edda93 --- /dev/null +++ b/Content.Shared/Inventory/SlotFlags.cs @@ -0,0 +1,29 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.Inventory; + +/// +/// Defines what slot types an item can fit into. +/// +[Serializable, NetSerializable] +[Flags] +public enum SlotFlags +{ + NONE = 0, + PREVENTEQUIP = 1 << 0, + HEAD = 1 << 1, + EYES = 1 << 2, + EARS = 1 << 3, + MASK = 1 << 4, + OUTERCLOTHING = 1 << 5, + INNERCLOTHING = 1 << 6, + NECK = 1 << 7, + BACK = 1 << 8, + BELT = 1 << 9, + GLOVES = 1 << 10, + IDCARD = 1 << 11, + POCKET = 1 << 12, + LEGS = 1 << 13, + FEET = 1 << 14, +} diff --git a/Content.Shared/Item/ItemSystem.cs b/Content.Shared/Item/ItemSystem.cs index 821d749849..7e7b6ebc96 100644 --- a/Content.Shared/Item/ItemSystem.cs +++ b/Content.Shared/Item/ItemSystem.cs @@ -1,6 +1,8 @@ +using Content.Shared.Inventory.Events; using Content.Shared.Verbs; using Robust.Shared.Containers; using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; using Robust.Shared.Localization; namespace Content.Shared.Item @@ -11,6 +13,38 @@ namespace Content.Shared.Item { base.Initialize(); SubscribeLocalEvent(AddPickupVerb); + + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); + + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + } + + private void OnHandleState(EntityUid uid, SharedItemComponent component, ref ComponentHandleState args) + { + if (args.Current is not ItemComponentState state) + return; + + component.Size = state.Size; + component.EquippedPrefix = state.EquippedPrefix; + component.Color = state.Color; + component.RsiPath = state.RsiPath; + } + + private void OnGetState(EntityUid uid, SharedItemComponent component, ref ComponentGetState args) + { + args.State = new ItemComponentState(component.Size, component.EquippedPrefix, component.Color, component.RsiPath); + } + + private void OnUnequipped(EntityUid uid, SharedSpriteComponent component, GotUnequippedEvent args) + { + component.Visible = true; + } + + private void OnEquipped(EntityUid uid, SharedSpriteComponent component, GotEquippedEvent args) + { + component.Visible = false; } private void AddPickupVerb(EntityUid uid, SharedItemComponent component, GetInteractionVerbsEvent args) diff --git a/Content.Shared/Item/SharedItemComponent.cs b/Content.Shared/Item/SharedItemComponent.cs index 5c83bb95c7..18ffef708a 100644 --- a/Content.Shared/Item/SharedItemComponent.cs +++ b/Content.Shared/Item/SharedItemComponent.cs @@ -4,6 +4,7 @@ using Content.Shared.Hands.Components; using Content.Shared.Interaction; using Content.Shared.Interaction.Helpers; using Content.Shared.Inventory; +using Content.Shared.Sound; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.IoC; @@ -19,7 +20,7 @@ namespace Content.Shared.Item /// Players can pick up, drop, and put items in bags, and they can be seen in player's hands. /// [NetworkedComponent()] - public abstract class SharedItemComponent : Component, IEquipped, IUnequipped, IInteractHand + public class SharedItemComponent : Component, IInteractHand { [Dependency] private readonly IEntityManager _entMan = default!; @@ -44,6 +45,7 @@ namespace Content.Shared.Item /// /// Part of the state of the sprite shown on the player when this item is in their hands. /// + // todo paul make this update slotvisuals on client on change [ViewVariables(VVAccess.ReadWrite)] public string? EquippedPrefix { @@ -58,6 +60,13 @@ namespace Content.Shared.Item [DataField("HeldPrefix")] private string? _equippedPrefix; + [ViewVariables] + [DataField("Slots")] + public SlotFlags SlotFlags = SlotFlags.PREVENTEQUIP; //Different from None, NONE allows equips if no slot flags are required + + [DataField("EquipSound")] + public SoundSpecifier? EquipSound { get; set; } = default!; + /// /// Color of the sprite shown on the player when this item is in their hands. /// @@ -65,7 +74,7 @@ namespace Content.Shared.Item public Color Color { get => _color; - protected set + set { _color = value; Dirty(); @@ -90,24 +99,6 @@ namespace Content.Shared.Item [DataField("sprite")] private string? _rsiPath; - public override ComponentState GetComponentState() - { - return new ItemComponentState(Size, EquippedPrefix, Color, RsiPath); - } - - public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) - { - base.HandleComponentState(curState, nextState); - - if (curState is not ItemComponentState state) - return; - - Size = state.Size; - EquippedPrefix = state.EquippedPrefix; - Color = state.Color; - RsiPath = state.RsiPath; - } - /// /// If a player can pick up this item. /// @@ -125,16 +116,6 @@ namespace Content.Shared.Item return user.InRangeUnobstructed(Owner, ignoreInsideBlocker: true, popup: popup); } - void IEquipped.Equipped(EquippedEventArgs eventArgs) - { - EquippedToSlot(); - } - - void IUnequipped.Unequipped(UnequippedEventArgs eventArgs) - { - RemovedFromSlot(); - } - bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { var user = eventArgs.User; diff --git a/Content.Shared/MobState/EntitySystems/MobStateSystem.cs b/Content.Shared/MobState/EntitySystems/MobStateSystem.cs index c4c2126f4d..d1d8ee05e7 100644 --- a/Content.Shared/MobState/EntitySystems/MobStateSystem.cs +++ b/Content.Shared/MobState/EntitySystems/MobStateSystem.cs @@ -26,9 +26,9 @@ namespace Content.Shared.MobState.EntitySystems SubscribeLocalEvent(OnInteractAttempt); SubscribeLocalEvent(OnThrowAttempt); SubscribeLocalEvent(OnSpeakAttempt); - SubscribeLocalEvent(OnEquipAttempt); + SubscribeLocalEvent(OnEquipAttempt); SubscribeLocalEvent(OnEmoteAttempt); - SubscribeLocalEvent(OnUnequipAttempt); + SubscribeLocalEvent(OnUnequipAttempt); SubscribeLocalEvent(OnAttackAttempt); SubscribeLocalEvent(OnDropAttempt); SubscribeLocalEvent(OnPickupAttempt); @@ -77,7 +77,7 @@ namespace Content.Shared.MobState.EntitySystems CheckAct(uid, component, args); } - private void OnEquipAttempt(EntityUid uid, MobStateComponent component, EquipAttemptEvent args) + private void OnEquipAttempt(EntityUid uid, MobStateComponent component, IsEquippingAttemptEvent args) { CheckAct(uid, component, args); } @@ -87,7 +87,7 @@ namespace Content.Shared.MobState.EntitySystems CheckAct(uid, component, args); } - private void OnUnequipAttempt(EntityUid uid, MobStateComponent component, UnequipAttemptEvent args) + private void OnUnequipAttempt(EntityUid uid, MobStateComponent component, IsUnequippingAttemptEvent args) { CheckAct(uid, component, args); } diff --git a/Content.Shared/PDA/PDAComponent.cs b/Content.Shared/PDA/PDAComponent.cs index 6740d766dd..087f58500b 100644 --- a/Content.Shared/PDA/PDAComponent.cs +++ b/Content.Shared/PDA/PDAComponent.cs @@ -22,7 +22,7 @@ namespace Content.Shared.PDA // Really this should just be using ItemSlot.StartingItem. However, seeing as we have so many different starting // PDA's and no nice way to inherit the other fields from the ItemSlot data definition, this makes the yaml much // nicer to read. - [DataField("idCard", customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? IdCard; [ViewVariables] public IdCardComponent? ContainedID; diff --git a/Content.Shared/Roles/StartingGearPrototype.cs b/Content.Shared/Roles/StartingGearPrototype.cs index edd5f9669a..42631fbda7 100644 --- a/Content.Shared/Roles/StartingGearPrototype.cs +++ b/Content.Shared/Roles/StartingGearPrototype.cs @@ -4,7 +4,6 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.ViewVariables; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Shared.Roles { @@ -12,7 +11,7 @@ namespace Content.Shared.Roles public class StartingGearPrototype : IPrototype { // TODO: Custom TypeSerializer for dictionary value prototype IDs - [DataField("equipment")] private Dictionary _equipment = new(); + [DataField("equipment")] private Dictionary _equipment = new(); /// /// if empty, there is no skirt override - instead the uniform provided in equipment is added. @@ -37,26 +36,19 @@ namespace Content.Shared.Roles [DataField("id", required: true)] public string ID { get; } = string.Empty; - public string GetGear(Slots slot, HumanoidCharacterProfile? profile) + public string GetGear(string slot, HumanoidCharacterProfile? profile) { if (profile != null) { - if (slot == Slots.INNERCLOTHING && profile.Clothing == ClothingPreference.Jumpskirt && !string.IsNullOrEmpty(_innerClothingSkirt)) + if (slot == "jumpsuit" && profile.Clothing == ClothingPreference.Jumpskirt && !string.IsNullOrEmpty(_innerClothingSkirt)) return _innerClothingSkirt; - if (slot == Slots.BACKPACK && profile.Backpack == BackpackPreference.Satchel && !string.IsNullOrEmpty(_satchel)) + if (slot == "back" && profile.Backpack == BackpackPreference.Satchel && !string.IsNullOrEmpty(_satchel)) return _satchel; - if (slot == Slots.BACKPACK && profile.Backpack == BackpackPreference.Duffelbag && !string.IsNullOrEmpty(_duffelbag)) + if (slot == "back" && profile.Backpack == BackpackPreference.Duffelbag && !string.IsNullOrEmpty(_duffelbag)) return _duffelbag; } - if (_equipment.ContainsKey(slot)) - { - return _equipment[slot]; - } - else - { - return ""; - } + return _equipment.TryGetValue(slot, out var equipment) ? equipment : string.Empty; } } } diff --git a/Content.Shared/Strip/Components/SharedStrippableComponent.cs b/Content.Shared/Strip/Components/SharedStrippableComponent.cs index 165d693c1a..0efc8863ed 100644 --- a/Content.Shared/Strip/Components/SharedStrippableComponent.cs +++ b/Content.Shared/Strip/Components/SharedStrippableComponent.cs @@ -6,7 +6,6 @@ using Content.Shared.Hands.Components; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; -using static Content.Shared.Inventory.EquipmentSlotDefines; namespace Content.Shared.Strip.Components { @@ -40,9 +39,9 @@ namespace Content.Shared.Strip.Components [NetSerializable, Serializable] public class StrippingInventoryButtonPressed : BoundUserInterfaceMessage { - public Slots Slot { get; } + public string Slot { get; } - public StrippingInventoryButtonPressed(Slots slot) + public StrippingInventoryButtonPressed(string slot) { Slot = slot; } @@ -73,11 +72,11 @@ namespace Content.Shared.Strip.Components [NetSerializable, Serializable] public class StrippingBoundUserInterfaceState : BoundUserInterfaceState { - public Dictionary Inventory { get; } + public Dictionary<(string ID, string Name), string> Inventory { get; } public Dictionary Hands { get; } public Dictionary Handcuffs { get; } - public StrippingBoundUserInterfaceState(Dictionary inventory, Dictionary hands, Dictionary handcuffs) + public StrippingBoundUserInterfaceState(Dictionary<(string ID, string Name), string> inventory, Dictionary hands, Dictionary handcuffs) { Inventory = inventory; Hands = hands; diff --git a/Content.Shared/Stunnable/SharedStunSystem.cs b/Content.Shared/Stunnable/SharedStunSystem.cs index 92d85fcaa9..faf5eb7ae4 100644 --- a/Content.Shared/Stunnable/SharedStunSystem.cs +++ b/Content.Shared/Stunnable/SharedStunSystem.cs @@ -56,8 +56,8 @@ namespace Content.Shared.Stunnable SubscribeLocalEvent(OnDropAttempt); SubscribeLocalEvent(OnPickupAttempt); SubscribeLocalEvent(OnAttackAttempt); - SubscribeLocalEvent(OnEquipAttempt); - SubscribeLocalEvent(OnUnequipAttempt); + SubscribeLocalEvent(OnEquipAttempt); + SubscribeLocalEvent(OnUnequipAttempt); } private void OnSlowGetState(EntityUid uid, SlowedDownComponent component, ref ComponentGetState args) @@ -256,14 +256,16 @@ namespace Content.Shared.Stunnable args.Cancel(); } - private void OnEquipAttempt(EntityUid uid, StunnedComponent stunned, EquipAttemptEvent args) + private void OnEquipAttempt(EntityUid uid, StunnedComponent stunned, IsEquippingAttemptEvent args) { - args.Cancel(); + if(args.Equipee == uid) + args.Cancel(); } - private void OnUnequipAttempt(EntityUid uid, StunnedComponent stunned, UnequipAttemptEvent args) + private void OnUnequipAttempt(EntityUid uid, StunnedComponent stunned, IsUnequippingAttemptEvent args) { - args.Cancel(); + if(args.Unequipee == uid) + args.Cancel(); } #endregion diff --git a/Content.Tests/Shared/EquipmentSlotDefinesTest.cs b/Content.Tests/Shared/EquipmentSlotDefinesTest.cs deleted file mode 100644 index 544ccaeb70..0000000000 --- a/Content.Tests/Shared/EquipmentSlotDefinesTest.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Linq; -using Content.Shared.Inventory; -using NUnit.Framework; -using static Content.Shared.Inventory.EquipmentSlotDefines; - -namespace Content.Tests.Shared -{ - [TestFixture] - [Parallelizable(ParallelScope.All)] - [TestOf(typeof(EquipmentSlotDefines))] - public class EquipmentSlotDefinesTest - { - /// - /// Test that all slots are contained in - /// - [Test] - public void TestAllSlotsContainsAll() - { - foreach (var slotObj in Enum.GetValues(typeof(Slots))) - { - var slot = (Slots) slotObj; - - if (slot == Slots.NONE || slot == Slots.LAST) - { - // Not real slots, skip these. - continue; - } - - Assert.That(AllSlots.Contains(slot)); - } - } - - /// - /// Test that every slot has an entry in . - /// - [Test] - public void TestSlotNamesContainsAll() - { - foreach (var slot in AllSlots) - { - Assert.That(SlotNames, Contains.Key(slot)); - } - } - - /// - /// Test that every slot has an entry in . - /// - [Test] - public void TestSlotMasksContainsAll() - { - foreach (var slot in AllSlots) - { - Assert.That(SlotMasks, Contains.Key(slot)); - } - } - } -} diff --git a/Resources/Locale/en-US/inventory/components/human-inventory-controller-component.ftl b/Resources/Locale/en-US/inventory/components/human-inventory-controller-component.ftl index df8dd6d52b..05c1653449 100644 --- a/Resources/Locale/en-US/inventory/components/human-inventory-controller-component.ftl +++ b/Resources/Locale/en-US/inventory/components/human-inventory-controller-component.ftl @@ -1,5 +1 @@ -human-inventory-controller-component-need-uniform-to-store-in-id-slot-text = You need a uniform to store something in your ID slot! -human-inventory-controller-component-need-uniform-to-store-in-pockets-text = You need a uniform to store something in your pockets! -human-inventory-controller-component-too-large-text = This is too large! - -set-outfit-verb-get-data-text = Set Outfit \ No newline at end of file +set-outfit-verb-get-data-text = Set Outfit diff --git a/Resources/Locale/en-US/inventory/components/inventory-component.ftl b/Resources/Locale/en-US/inventory/components/inventory-component.ftl index 98d11a18ae..79943d914e 100644 --- a/Resources/Locale/en-US/inventory/components/inventory-component.ftl +++ b/Resources/Locale/en-US/inventory/components/inventory-component.ftl @@ -1,3 +1,4 @@ -inventory-component-on-equip-cannot = You can't equip this! inventory-component-can-equip-cannot = You can't equip this! -inventory-component-can-equip-does-not-fit = This doesn't fit! \ No newline at end of file +inventory-component-can-equip-does-not-fit = This doesn't fit! + +inventory-component-can-unequip-cannot = You can't unequip this! diff --git a/Resources/Locale/en-US/traitor-death-match/components/traitor-death-match-redemption-component.ftl b/Resources/Locale/en-US/traitor-death-match/components/traitor-death-match-redemption-component.ftl index badefc4976..cc710d0ce6 100644 --- a/Resources/Locale/en-US/traitor-death-match/components/traitor-death-match-redemption-component.ftl +++ b/Resources/Locale/en-US/traitor-death-match/components/traitor-death-match-redemption-component.ftl @@ -1,5 +1,4 @@ traitor-death-match-redemption-component-interact-using-main-message = The machine buzzes, and displays: {$secondMessage} -traitor-death-match-redemption-component-interact-using-no-inventory-message = "USER PDA OUT OF RANGE (0039)" traitor-death-match-redemption-component-interact-using-no-mind-message = "AUTHENTICATION FAILED (0045)" traitor-death-match-redemption-component-interact-using-no-user-mind-message = "AUTHENTICATION FAILED (0052)" traitor-death-match-redemption-component-interact-using-no-pda-message = GIVEN PDA IS NOT A PDA (0058)" @@ -9,4 +8,4 @@ traitor-death-match-redemption-component-interact-using-no-pda-in-pocket-message traitor-death-match-redemption-component-interact-using-tampering-detected = "TAMPERING DETECTED (0101)" traitor-death-match-redemption-component-interact-using-user-no-uplink-account-message = "USER PDA HAS NO UPLINK ACCOUNT (0102)" traitor-death-match-redemption-component-interact-using-victim-no-uplink-account-message = "USER PDA HAS NO UPLINK ACCOUNT (0108)" -traitor-death-match-redemption-component-interact-using-success-message = The machine plays a happy little tune, and displays: "SUCCESS: {$tcAmount} TC TRANSFERRED" \ No newline at end of file +traitor-death-match-redemption-component-interact-using-success-message = The machine plays a happy little tune, and displays: "SUCCESS: {$tcAmount} TC TRANSFERRED" diff --git a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml index 8aa43092ee..f11867c483 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml @@ -127,7 +127,7 @@ state: icon-ammo - type: Clothing sprite: Clothing/Back/Duffels/syndicate.rsi - ClothingPrefix: ammo + HeldPrefix: ammo - type: entity parent: ClothingBackpackDuffelSyndicate @@ -139,7 +139,7 @@ state: icon-med - type: Clothing sprite: Clothing/Back/Duffels/syndicate.rsi - ClothingPrefix: med + HeldPrefix: med - type: entity parent: ClothingBackpackDuffel diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index a6eaa6ede3..d5107c0679 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -36,7 +36,6 @@ - type: Clothing sprite: Clothing/Eyes/Glasses/gar.rsi HeldPrefix: alt - ClothingPrefix: alt - type: MeleeWeapon damage: types: @@ -53,7 +52,7 @@ state: icon-super - type: Clothing sprite: Clothing/Eyes/Glasses/gar.rsi - ClothingPrefix: super + HeldPrefix: super - type: MeleeWeapon damage: types: diff --git a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml index d3c636aee7..69c29f9a49 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml @@ -5,7 +5,7 @@ components: - type: Clothing Slots: - - Helmet + - HEAD - type: Sprite state: icon @@ -16,7 +16,7 @@ components: - type: Clothing Slots: - - Helmet + - HEAD - type: Sprite state: icon @@ -56,7 +56,6 @@ visible: false - type: Clothing HeldPrefix: off - ClothingPrefix: off - type: PointLight enabled: false radius: 3 diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml b/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml index d38399859b..0126d5a4de 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml @@ -11,7 +11,6 @@ visible: false - type: Clothing HeldPrefix: off - ClothingPrefix: off - type: PointLight enabled: false radius: 3 diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml index 9a32580f21..5e7bc13f50 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml @@ -5,7 +5,7 @@ components: - type: Clothing Slots: - - shoes + - FEET - type: Sprite state: icon - type: Extractable diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index ec3952b272..6eef69a7ab 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -419,9 +419,8 @@ QuickEquip: false sprite: Mobs/Animals/mouse.rsi HeldPrefix: 0 - ClothingPrefix: 0 Slots: - - Helmet + - HEAD - type: Physics - type: Fixtures fixtures: @@ -478,7 +477,6 @@ sprite: Mobs/Animals/mouse.rsi - type: Clothing HeldPrefix: 1 - ClothingPrefix: 1 - type: Appearance visuals: - type: DamageStateVisualizer @@ -498,7 +496,6 @@ sprite: Mobs/Animals/mouse.rsi - type: Clothing HeldPrefix: 1 - ClothingPrefix: 2 - type: Appearance visuals: - type: DamageStateVisualizer diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 1e007e2a0f..97706e30f7 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -20,7 +20,6 @@ - type: Eye - type: CameraRecoil - type: Examiner - - type: HumanInventoryController - type: CanHostGuardian - type: AiFactionTag factions: diff --git a/Resources/Prototypes/Entities/Mobs/Player/slime.yml b/Resources/Prototypes/Entities/Mobs/Player/slime.yml index b9744d1e02..ae4406be9b 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/slime.yml @@ -15,7 +15,6 @@ - type: Eye - type: CameraRecoil - type: Examiner - - type: HumanInventoryController - type: AiFactionTag factions: - NanoTrasen diff --git a/Resources/Prototypes/Entities/Mobs/Player/vox.yml b/Resources/Prototypes/Entities/Mobs/Player/vox.yml index 39b5de03fb..9ff33beab3 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/vox.yml @@ -16,7 +16,6 @@ - type: Eye - type: CameraRecoil - type: Examiner - - type: HumanInventoryController - type: AiFactionTag factions: - NanoTrasen diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 90290f491f..9839e988f9 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -108,7 +108,7 @@ sprite: Mobs/Customization/masking_helpers.rsi state: female_full visible: false - - map: [ "enum.Slots.INNERCLOTHING" ] + - map: [ "jumpsuit" ] shader: StencilDraw - map: [ "enum.HumanoidVisualLayers.LHand" ] color: "#e8b59b" @@ -131,25 +131,25 @@ sprite: Objects/Misc/handcuffs.rsi state: body-overlay-2 visible: false - - map: [ "enum.Slots.IDCARD" ] - - map: [ "enum.Slots.GLOVES" ] - - map: [ "enum.Slots.SHOES" ] - - map: [ "enum.Slots.EARS" ] - - map: [ "enum.Slots.OUTERCLOTHING" ] - - map: [ "enum.Slots.EYES" ] - - map: [ "enum.Slots.BELT" ] - - map: [ "enum.Slots.NECK" ] - - map: [ "enum.Slots.BACKPACK" ] + - map: [ "id" ] + - map: [ "gloves" ] + - map: [ "shoes" ] + - map: [ "ears" ] + - map: [ "outerClothing" ] + - map: [ "eyes" ] + - map: [ "belt" ] + - map: [ "neck" ] + - map: [ "back" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] state: shaved sprite: Mobs/Customization/human_facial_hair.rsi - map: [ "enum.HumanoidVisualLayers.Hair" ] state: bald sprite: Mobs/Customization/human_hair.rsi - - map: [ "enum.Slots.MASK" ] - - map: [ "enum.Slots.HEAD" ] - - map: [ "enum.Slots.POCKET1" ] - - map: [ "enum.Slots.POCKET2" ] + - map: [ "mask" ] + - map: [ "head" ] + - map: [ "pocket1" ] + - map: [ "pocket2" ] - type: Physics bodyType: KinematicController - type: Fixtures @@ -303,6 +303,7 @@ components: - type: Hands - type: Inventory + - type: ContainerContainer - type: Icon sprite: Mobs/Species/Human/parts.rsi state: full @@ -354,7 +355,7 @@ sprite: Mobs/Customization/masking_helpers.rsi state: female_full visible: false - - map: ["enum.Slots.INNERCLOTHING"] + - map: ["jumpsuit"] shader: StencilDraw - map: ["enum.HumanoidVisualLayers.LHand"] color: "#e8b59b" @@ -369,25 +370,25 @@ sprite: Objects/Misc/handcuffs.rsi state: body-overlay-2 visible: false - - map: ["enum.Slots.IDCARD"] - - map: ["enum.Slots.GLOVES"] - - map: ["enum.Slots.SHOES"] - - map: ["enum.Slots.EARS"] - - map: ["enum.Slots.OUTERCLOTHING"] - - map: ["enum.Slots.EYES"] - - map: ["enum.Slots.BELT"] - - map: ["enum.Slots.NECK"] - - map: ["enum.Slots.BACKPACK"] + - map: ["id"] + - map: ["gloves"] + - map: ["shoes"] + - map: ["ears"] + - map: ["outerClothing"] + - map: ["eyes"] + - map: ["belt"] + - map: ["neck"] + - map: ["back"] - map: ["enum.HumanoidVisualLayers.FacialHair"] state: shaved sprite: Mobs/Customization/human_facial_hair.rsi - map: ["enum.HumanoidVisualLayers.Hair"] state: bald sprite: Mobs/Customization/human_hair.rsi - - map: ["enum.Slots.MASK"] - - map: ["enum.Slots.HEAD"] - - map: [ "enum.Slots.POCKET1" ] - - map: [ "enum.Slots.POCKET2" ] + - map: ["mask"] + - map: ["head"] + - map: [ "pocket1" ] + - map: [ "pocket2" ] - map: ["hand-left"] - map: ["hand-right"] - type: Physics diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index 09f4a26af8..b787424d9d 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -48,7 +48,7 @@ sprite: Mobs/Customization/masking_helpers.rsi state: female_full visible: false - - map: [ "enum.Slots.INNERCLOTHING" ] + - map: [ "jumpsuit" ] shader: StencilDraw - map: [ "enum.HumanoidVisualLayers.LHand" ] color: "#b8b8b8" @@ -71,25 +71,25 @@ sprite: Objects/Misc/handcuffs.rsi state: body-overlay-2 visible: false - - map: [ "enum.Slots.IDCARD" ] - - map: [ "enum.Slots.GLOVES" ] - - map: [ "enum.Slots.SHOES" ] - - map: [ "enum.Slots.EARS" ] - - map: [ "enum.Slots.OUTERCLOTHING" ] - - map: [ "enum.Slots.EYES" ] - - map: [ "enum.Slots.BELT" ] - - map: [ "enum.Slots.NECK" ] - - map: [ "enum.Slots.BACKPACK" ] + - map: [ "id" ] + - map: [ "gloves" ] + - map: [ "shoes" ] + - map: [ "ears" ] + - map: [ "outerClothing" ] + - map: [ "eyes" ] + - map: [ "belt" ] + - map: [ "neck" ] + - map: [ "back" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] state: shaved sprite: Mobs/Customization/human_facial_hair.rsi - map: [ "enum.HumanoidVisualLayers.Hair" ] state: bald sprite: Mobs/Customization/human_hair.rsi - - map: [ "enum.Slots.MASK" ] - - map: [ "enum.Slots.HEAD" ] - - map: [ "enum.Slots.POCKET1" ] - - map: [ "enum.Slots.POCKET2" ] + - map: [ "mask" ] + - map: [ "head" ] + - map: [ "pocket1" ] + - map: [ "pocket2" ] - type: Body template: HumanoidTemplate preset: SlimePreset diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index e40eed1171..4d20d1f48c 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -42,7 +42,7 @@ # sprite: Mobs/Customization/masking_helpers.rsi # state: female_full # visible: false - #- map: [ "enum.Slots.INNERCLOTHING" ] + #- map: [ "jumpsuit" ] # shader: StencilDraw - map: [ "enum.HumanoidVisualLayers.LHand" ] sprite: Mobs/Species/Vox/parts.rsi @@ -61,25 +61,25 @@ sprite: Objects/Misc/handcuffs.rsi state: body-overlay-2 visible: false - - map: [ "enum.Slots.IDCARD" ] - - map: [ "enum.Slots.GLOVES" ] - - map: [ "enum.Slots.SHOES" ] - - map: [ "enum.Slots.EARS" ] - - map: [ "enum.Slots.OUTERCLOTHING" ] - - map: [ "enum.Slots.EYES" ] - - map: [ "enum.Slots.BELT" ] - - map: [ "enum.Slots.NECK" ] - - map: [ "enum.Slots.BACKPACK" ] + - map: [ "id" ] + - map: [ "gloves" ] + - map: [ "shoes" ] + - map: [ "ears" ] + - map: [ "outerClothing" ] + - map: [ "eyes" ] + - map: [ "belt" ] + - map: [ "neck" ] + - map: [ "back" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] state: shaved sprite: Mobs/Customization/human_facial_hair.rsi - map: [ "enum.HumanoidVisualLayers.Hair" ] state: bald sprite: Mobs/Customization/human_hair.rsi - - map: [ "enum.Slots.MASK" ] - - map: [ "enum.Slots.HEAD" ] - - map: [ "enum.Slots.POCKET1" ] - - map: [ "enum.Slots.POCKET2" ] + - map: [ "mask" ] + - map: [ "head" ] + - map: [ "pocket1" ] + - map: [ "pocket2" ] - type: Body template: HumanoidTemplate preset: VoxPreset diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 218d9d81a2..f3334bdfe1 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -56,7 +56,7 @@ description: Why isn't it gray? components: - type: PDA - idCard: AssistantIDCard + id: AssistantIDCard - type: entity parent: BasePDA @@ -65,7 +65,7 @@ description: Covered in grease and flour. components: - type: PDA - idCard: ChefIDCard + id: ChefIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -80,7 +80,7 @@ description: Has an earthy scent. components: - type: PDA - idCard: BotanistIDCard + id: BotanistIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -95,7 +95,7 @@ description: Looks can be deceiving. components: - type: PDA - idCard: ClownIDCard + id: ClownIDCard penSlot: startingItem: CrayonOrange # no pink crayon?!? # Maybe this is a bad idea. @@ -140,7 +140,7 @@ description: Suprisingly not on mute. components: - type: PDA - idCard: MimeIDCard + id: MimeIDCard idSlot: name: ID Card whitelist: @@ -160,7 +160,7 @@ description: God's chosen PDA. components: - type: PDA - idCard: ChaplainIDCard + id: ChaplainIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -175,7 +175,7 @@ description: PDA for the guy that orders the guns. components: - type: PDA - idCard: QuartermasterIDCard + id: QuartermasterIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -190,7 +190,7 @@ description: PDA for the guys that order the pizzas. components: - type: PDA - idCard: CargoIDCard + id: CargoIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -205,7 +205,7 @@ description: Smells like beer. components: - type: PDA - idCard: BartenderIDCard + id: BartenderIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -221,7 +221,7 @@ description: Smells like bleach. components: - type: PDA - idCard: JanitorIDCard + id: JanitorIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -236,7 +236,7 @@ description: Surprisingly no different from your PDA. components: - type: PDA - idCard: CaptainIDCard + id: CaptainIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -252,7 +252,7 @@ description: Looks like it's been chewed on. components: - type: PDA - idCard: HoPIDCard + id: HoPIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -268,7 +268,7 @@ description: Looks like it's barely been used. components: - type: PDA - idCard: CEIDCard + id: CEIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -284,7 +284,7 @@ description: Rugged and well-worn. components: - type: PDA - idCard: EngineeringIDCard + id: EngineeringIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -299,7 +299,7 @@ description: Extraordinarily shiny and sterile. components: - type: PDA - idCard: CMOIDCard + id: CMOIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -314,7 +314,7 @@ description: Shiny and sterile. components: - type: PDA - idCard: MedicalIDCard + id: MedicalIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -329,7 +329,7 @@ description: It has a few discolored blotches here and there. components: - type: PDA - idCard: ChemistIDCard + id: ChemistIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -344,7 +344,7 @@ description: It appears surprisingly ordinary. components: - type: PDA - idCard: RDIDCard + id: RDIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -359,7 +359,7 @@ description: It's covered with an unknown gooey substance. components: - type: PDA - idCard: ResearchIDCard + id: ResearchIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -374,7 +374,7 @@ description: Whosoever bears this PDA is the law. components: - type: PDA - idCard: HoSIDCard + id: HoSIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -389,7 +389,7 @@ description: The OS appears to have been jailbroken. components: - type: PDA - idCard: WardenIDCard + id: WardenIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -404,7 +404,7 @@ description: Red to hide the stains of assistant blood. components: - type: PDA - idCard: SecurityIDCard + id: SecurityIDCard - type: Appearance visuals: - type: PDAVisualizer @@ -419,4 +419,4 @@ description: Colored the numbing grey of bureaucracy. components: - type: PDA - idCard: CentcomIDCardSyndie + id: CentcomIDCardSyndie diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 030d14690e..28a56ecb35 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -134,7 +134,7 @@ QuickEquip: false sprite: Objects/Fun/ducky.rsi Slots: - - Helmet + - HEAD - type: ItemCooldown - type: EmitSoundOnUse sound: diff --git a/Resources/Prototypes/Entities/Objects/Materials/materials.yml b/Resources/Prototypes/Entities/Objects/Materials/materials.yml index 7a49f6547a..4ebd393648 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/materials.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/materials.yml @@ -256,9 +256,8 @@ - type: Clothing sprite: Clothing/Head/Misc/hides.rsi HeldPrefix: bear - ClothingPrefix: bear Slots: - - Helmet + - HEAD - type: entity parent: MaterialBase @@ -271,9 +270,8 @@ # - type: Clothing # sprite: Clothing/Head/Misc/hides.rsi # HeldPrefix: cat - # ClothingPrefix: cat # Slots: - # - Helmet + # - HEAD - type: entity parent: MaterialBase @@ -285,7 +283,6 @@ state: corgihide - type: Clothing sprite: Clothing/Head/Misc/hides.rsi - # HeldPrefix: corgi - ClothingPrefix: corgi2 + HeldPrefix: corgi Slots: - - Helmet + - HEAD diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml index ef91ab5a89..b60df3dcc8 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml @@ -15,7 +15,7 @@ size: 100 sprite: Objects/Tools/bucket.rsi Slots: - - Helmet + - HEAD - type: Bucket - type: SolutionContainerManager solutions: diff --git a/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml new file mode 100644 index 0000000000..530e88303b --- /dev/null +++ b/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml @@ -0,0 +1,90 @@ +- type: inventoryTemplate + id: human + slots: + - name: shoes + slotTexture: shoes + slotFlags: FEET + uiContainer: Top + uiWindowPos: 1,3 + displayName: Shoes + - name: jumpsuit + slotTexture: uniform + slotFlags: INNERCLOTHING + uiContainer: Top + uiWindowPos: 0,2 + displayName: Jumpsuit + - name: outerClothing + slotTexture: suit + slotFlags: OUTERCLOTHING + uiContainer: Top + uiWindowPos: 1,2 + displayName: Suit + - name: gloves + slotTexture: gloves + slotFlags: GLOVES + uiContainer: Top + uiWindowPos: 2,2 + displayName: Gloves + - name: neck + slotTexture: neck + slotFlags: NECK + uiContainer: Top + uiWindowPos: 0,1 + displayName: Neck + - name: mask + slotTexture: mask + slotFlags: MASK + uiContainer: Top + uiWindowPos: 1,1 + displayName: Mask + - name: eyes + slotTexture: glasses + slotFlags: EYES + uiContainer: Top + uiWindowPos: 0,0 + displayName: Eyes + - name: ears + slotTexture: ears + slotFlags: EARS + uiContainer: Top + uiWindowPos: 2,0 + displayName: Ears + - name: head + slotTexture: head + slotFlags: HEAD + uiContainer: Top + uiWindowPos: 1,0 + displayName: Head + - name: pocket1 + slotTexture: pocket + slotFlags: POCKET + uiContainer: BottomRight + uiWindowPos: 0,3 + dependsOn: jumpsuit + displayName: Pocket 1 + - name: pocket2 + slotTexture: pocket + slotFlags: POCKET + uiContainer: BottomRight + uiWindowPos: 2,3 + dependsOn: jumpsuit + displayName: Pocket 2 + - name: id + slotTexture: id + slotFlags: IDCARD + uiContainer: BottomRight + uiWindowPos: 2,1 + dependsOn: jumpsuit + displayName: ID + - name: belt + slotTexture: belt + slotFlags: BELT + uiContainer: BottomLeft + uiWindowPos: 3,1 + displayName: Belt + - name: back + slotTexture: back + slotFlags: BACK + uiContainer: BottomLeft + uiWindowPos: 3,0 + displayName: Back diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml b/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml index 67073f0f9a..636b212649 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml @@ -15,10 +15,10 @@ id: CargoTechGear equipment: head: ClothingHeadHatCargosoft - innerclothing: ClothingUniformJumpsuitCargo - backpack: ClothingBackpackFilled + jumpsuit: ClothingUniformJumpsuitCargo + back: ClothingBackpackFilled shoes: ClothingShoesColorBlack - idcard: CargoPDA + id: CargoPDA ears: ClothingHeadsetCargo innerclothingskirt: ClothingUniformJumpskirtCargo satchel: ClothingBackpackSatchelFilled diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml index b77e4d90dd..0bc740a0ec 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml @@ -16,10 +16,10 @@ id: QuartermasterGear equipment: head: ClothingHeadHatCargosoft - innerclothing: ClothingUniformJumpsuitQM - backpack: ClothingBackpackFilled + jumpsuit: ClothingUniformJumpsuitQM + back: ClothingBackpackFilled shoes: ClothingShoesColorBrown - idcard: QuartermasterPDA + id: QuartermasterPDA ears: ClothingHeadsetCargo innerclothingskirt: ClothingUniformJumpskirtQM satchel: ClothingBackpackSatchelFilled diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml b/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml index 58a4537872..4c1a4df096 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml @@ -12,10 +12,10 @@ - type: startingGear id: AssistantGear equipment: - innerclothing: ClothingUniformJumpsuitColorGrey - backpack: ClothingBackpackFilled + jumpsuit: ClothingUniformJumpsuitColorGrey + back: ClothingBackpackFilled shoes: ClothingShoesColorBlack - idcard: AssistantPDA + id: AssistantPDA ears: ClothingHeadsetService innerclothingskirt: ClothingUniformJumpskirtColorGrey satchel: ClothingBackpackSatchelFilled diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml b/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml index 072ce54edf..b89d950d44 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml @@ -15,11 +15,11 @@ id: BartenderGear equipment: head: ClothingHeadHatTophat - innerclothing: ClothingUniformJumpsuitBartender + jumpsuit: ClothingUniformJumpsuitBartender outerclothing: ClothingOuterVestKevlar - backpack: ClothingBackpackFilled + back: ClothingBackpackFilled shoes: ClothingShoesColorBlack - idcard: BartenderPDA + id: BartenderPDA ears: ClothingHeadsetService innerclothingskirt: ClothingUniformJumpskirtBartender satchel: ClothingBackpackSatchelFilled diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml b/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml index a89062cab3..df14066993 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml @@ -14,10 +14,10 @@ - type: startingGear id: BotanistGear equipment: - innerclothing: ClothingUniformJumpsuitHydroponics - backpack: ClothingBackpackHydroponicsFilled + jumpsuit: ClothingUniformJumpsuitHydroponics + back: ClothingBackpackHydroponicsFilled shoes: ClothingShoesColorBrown - idcard: BotanistPDA + id: BotanistPDA ears: ClothingHeadsetService outerclothing: ClothingOuterApronBotanist innerclothingskirt: ClothingUniformJumpskirtHydroponics diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml index 32830bbe75..a721827e6b 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml @@ -13,10 +13,10 @@ - type: startingGear id: ChaplainGear equipment: - innerclothing: ClothingUniformJumpsuitChaplain - backpack: ClothingBackpackFilled + jumpsuit: ClothingUniformJumpsuitChaplain + back: ClothingBackpackFilled shoes: ClothingShoesColorBlack - idcard: ChaplainPDA + id: ChaplainPDA ears: ClothingHeadsetService innerclothingskirt: ClothingUniformJumpskirtChaplain diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml index d4f1f0c6aa..54d914b0e5 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml @@ -14,11 +14,11 @@ - type: startingGear id: ChefGear equipment: - innerclothing: ClothingUniformJumpsuitChef + jumpsuit: ClothingUniformJumpsuitChef head: ClothingHeadHatChef - backpack: ClothingBackpackFilled + back: ClothingBackpackFilled shoes: ClothingShoesColorBlack - idcard: ChefPDA + id: ChefPDA ears: ClothingHeadsetService outerclothing: ClothingOuterApronChef innerclothingskirt: ClothingUniformJumpskirtChef diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml index 31ab7cc5dd..a9c532a84e 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml @@ -16,12 +16,12 @@ - type: startingGear id: ClownGear equipment: - innerclothing: ClothingUniformJumpsuitClown - backpack: ClothingBackpackClownFilled + jumpsuit: ClothingUniformJumpsuitClown + back: ClothingBackpackClownFilled shoes: ClothingShoesClown mask: ClothingMaskClown pocket1: BikeHorn - idcard: ClownPDA + id: ClownPDA ears: ClothingHeadsetService satchel: ClothingBackpackSatchelFilled duffelbag: ClothingBackpackDuffelClownFilled diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml b/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml index f45118b8e9..afde462ccc 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml @@ -17,11 +17,11 @@ - type: startingGear id: JanitorGear equipment: - innerclothing: ClothingUniformJumpsuitJanitor - backpack: ClothingBackpackFilled + jumpsuit: ClothingUniformJumpsuitJanitor + back: ClothingBackpackFilled shoes: ClothingShoesGaloshes head: ClothingHeadHatPurplesoft - idcard: JanitorPDA + id: JanitorPDA ears: ClothingHeadsetService belt: ClothingBeltJanitorFilled innerclothingskirt: ClothingUniformJumpskirtJanitor diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml index bfde71f7a8..43ab456936 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml @@ -13,8 +13,8 @@ - type: startingGear id: MimeGear equipment: - innerclothing: ClothingUniformJumpsuitMime - backpack: ClothingBackpackMimeFilled + jumpsuit: ClothingUniformJumpsuitMime + back: ClothingBackpackMimeFilled head: ClothingHeadHatBeret belt: ClothingBeltSuspenders gloves: ClothingHandsGlovesLatex @@ -22,7 +22,7 @@ pocket1: CrayonMime pocket2: Paper mask: ClothingMaskMime - idcard: MimePDA + id: MimePDA ears: ClothingHeadsetService innerclothingskirt: ClothingUniformJumpskirtMime satchel: ClothingBackpackSatchelFilled diff --git a/Resources/Prototypes/Roles/Jobs/Command/captain.yml b/Resources/Prototypes/Roles/Jobs/Command/captain.yml index 5e5a092b1a..4fc42c2ea1 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/captain.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/captain.yml @@ -39,18 +39,18 @@ - Kitchen - Chapel - Hydroponics - + - type: startingGear id: CaptainGear equipment: - innerclothing: ClothingUniformJumpsuitCaptain - backpack: ClothingBackpackCaptainFilled + jumpsuit: ClothingUniformJumpsuitCaptain + back: ClothingBackpackCaptainFilled shoes: ClothingShoesColorBlack head: ClothingHeadHatCaptain eyes: ClothingEyesGlassesSunglasses gloves: ClothingHandsGlovesCaptain outerclothing: ClothingOuterHardsuitCap - idcard: CaptainPDA + id: CaptainPDA ears: ClothingHeadsetAltCommand innerclothingskirt: ClothingUniformJumpskirtCaptain satchel: ClothingBackpackSatchelCaptainFilled diff --git a/Resources/Prototypes/Roles/Jobs/Command/centcom_official.yml b/Resources/Prototypes/Roles/Jobs/Command/centcom_official.yml index 39c58e7d13..f1a4219e34 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/centcom_official.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/centcom_official.yml @@ -14,13 +14,13 @@ - type: startingGear id: CentcomGear equipment: - innerclothing: ClothingUniformJumpsuitCentcomOfficial + jumpsuit: ClothingUniformJumpsuitCentcomOfficial shoes: ClothingShoesBootsJack head: ClothingHeadHatCentcom eyes: ClothingEyesGlassesSunglasses gloves: ClothingHandsGlovesColorBlack outerclothing: ClothingOuterVestKevlar - idcard: CentcomPDA + id: CentcomPDA ears: ClothingHeadsetAltCommand pocket1: Paper pocket2: Pen diff --git a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml index fa4ca29277..0a4e909440 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml @@ -26,11 +26,11 @@ - type: startingGear id: HoPGear equipment: - innerclothing: ClothingUniformJumpsuitHoP - backpack: ClothingBackpackFilled + jumpsuit: ClothingUniformJumpsuitHoP + back: ClothingBackpackFilled shoes: ClothingShoesColorBrown head: ClothingHeadHatHopcap - idcard: HoPPDA + id: HoPPDA ears: ClothingHeadsetAltCommand innerclothingskirt: ClothingUniformJumpskirtHoP satchel: ClothingBackpackSatchelFilled diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml index 0823b48999..c67d57f560 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml @@ -21,10 +21,10 @@ id: ChiefEngineerGear equipment: head: ClothingHeadHatHardhatWhite - innerclothing: ClothingUniformJumpsuitChiefEngineer - backpack: ClothingBackpackEngineeringFilled + jumpsuit: ClothingUniformJumpsuitChiefEngineer + back: ClothingBackpackEngineeringFilled shoes: ClothingShoesColorBrown - idcard: CEPDA + id: CEPDA ears: ClothingHeadsetEngineering belt: ClothingBeltChiefEngineerFilled innerclothingskirt: ClothingUniformJumpskirtChiefEngineer diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml index 803181b778..35ef0e8012 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml @@ -15,11 +15,11 @@ id: StationEngineerGear equipment: head: ClothingHeadHatHardhatYellow - innerclothing: ClothingUniformJumpsuitEngineering - backpack: ClothingBackpackEngineeringFilled + jumpsuit: ClothingUniformJumpsuitEngineering + back: ClothingBackpackEngineeringFilled shoes: ClothingShoesBootsWork outerclothing: ClothingOuterVestHazard - idcard: EngineerPDA + id: EngineerPDA belt: ClothingBeltUtilityFilled ears: ClothingHeadsetEngineering innerclothingskirt: ClothingUniformJumpskirtEngineering diff --git a/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml b/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml index 66d5ce2848..10f7915ffc 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml @@ -10,15 +10,15 @@ - Medical - Chemistry - Maintenance - + - type: startingGear id: ChemistGear equipment: - innerclothing: ClothingUniformJumpsuitChemistry - backpack: ClothingBackpackChemistryFilled + jumpsuit: ClothingUniformJumpsuitChemistry + back: ClothingBackpackChemistryFilled shoes: ClothingShoesColorWhite outerclothing: ClothingOuterCoatLabChem - idcard: ChemistryPDA + id: ChemistryPDA ears: ClothingHeadsetMedical belt: ClothingBeltMedical pocket1: HandLabeler diff --git a/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml index 79627ff8aa..66c44f1610 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml @@ -22,11 +22,11 @@ - type: startingGear id: CMOGear equipment: - innerclothing: ClothingUniformJumpsuitCMO - backpack: ClothingBackpackMedicalFilled + jumpsuit: ClothingUniformJumpsuitCMO + back: ClothingBackpackMedicalFilled shoes: ClothingShoesColorBrown outerclothing: ClothingOuterCoatLabCmo - idcard: CMOPDA + id: CMOPDA ears: ClothingHeadsetAltMedical belt: ClothingBeltMedical innerclothingskirt: ClothingUniformJumpskirtCMO diff --git a/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml index 4fca77ec92..dcda6e53d8 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml @@ -13,11 +13,11 @@ - type: startingGear id: DoctorGear equipment: - innerclothing: ClothingUniformJumpsuitMedicalDoctor - backpack: ClothingBackpackMedicalFilled + jumpsuit: ClothingUniformJumpsuitMedicalDoctor + back: ClothingBackpackMedicalFilled shoes: ClothingShoesColorWhite outerclothing: ClothingOuterCoatLab - idcard: MedicalPDA + id: MedicalPDA ears: ClothingHeadsetMedical belt: ClothingBeltMedical innerclothingskirt: ClothingUniformJumpskirtMedicalDoctor diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index e6989a9ec1..707cc7da42 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -19,11 +19,11 @@ - type: startingGear id: ResearchDirectorGear equipment: - innerclothing: ClothingUniformJumpsuitResearchDirector - backpack: ClothingBackpackScienceFilled + jumpsuit: ClothingUniformJumpsuitResearchDirector + back: ClothingBackpackScienceFilled shoes: ClothingShoesColorBrown outerclothing: ClothingOuterCoatLab - idcard: RnDPDA + id: RnDPDA ears: ClothingHeadsetScience innerclothingskirt: ClothingUniformJumpskirtResearchDirector satchel: ClothingBackpackSatchelScienceFilled diff --git a/Resources/Prototypes/Roles/Jobs/Science/scientist.yml b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml index 54a3054a1e..fa78c3c2e8 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/scientist.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml @@ -13,11 +13,11 @@ - type: startingGear id: ScientistGear equipment: - innerclothing: ClothingUniformJumpsuitScientist - backpack: ClothingBackpackScienceFilled + jumpsuit: ClothingUniformJumpsuitScientist + back: ClothingBackpackScienceFilled shoes: ClothingShoesColorWhite outerclothing: ClothingOuterCoatLab - idcard: SciencePDA + id: SciencePDA ears: ClothingHeadsetScience innerclothingskirt: ClothingUniformJumpskirtScientist satchel: ClothingBackpackSatchelScienceFilled diff --git a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml index 402746afb1..d8a4d39db5 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml @@ -22,13 +22,13 @@ - type: startingGear id: HoSGear equipment: - innerclothing: ClothingUniformJumpsuitHoS - backpack: ClothingBackpackSecurityFilled + jumpsuit: ClothingUniformJumpsuitHoS + back: ClothingBackpackSecurityFilled shoes: ClothingShoesBootsJack outerclothing: ClothingOuterCoatHoSTrench eyes: ClothingEyesGlassesSecurity head: ClothingHeadHatBeretHoS - idcard: HoSPDA + id: HoSPDA ears: ClothingHeadsetAltSecurity belt: ClothingBeltSecurityFilled innerclothingskirt: ClothingUniformJumpskirtHoS diff --git a/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml index 40df997ac9..cb00271645 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml @@ -15,13 +15,13 @@ - type: startingGear id: SecurityOfficerGear equipment: - innerclothing: ClothingUniformJumpsuitSec - backpack: ClothingBackpackSecurityFilled + jumpsuit: ClothingUniformJumpsuitSec + back: ClothingBackpackSecurityFilled shoes: ClothingShoesBootsJack eyes: ClothingEyesGlassesSecurity head: ClothingHeadHelmetHelmetOld outerclothing: ClothingOuterVestKevlar - idcard: SecurityPDA + id: SecurityPDA ears: ClothingHeadsetSecurity belt: ClothingBeltSecurityFilled innerclothingskirt: ClothingUniformJumpskirtSec diff --git a/Resources/Prototypes/Roles/Jobs/Security/warden.yml b/Resources/Prototypes/Roles/Jobs/Security/warden.yml index b191277408..0dd17dcd73 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/warden.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/warden.yml @@ -17,12 +17,12 @@ id: WardenGear equipment: head: ClothingHeadHatWarden - innerclothing: ClothingUniformJumpsuitWarden - backpack: ClothingBackpackSecurityFilled + jumpsuit: ClothingUniformJumpsuitWarden + back: ClothingBackpackSecurityFilled shoes: ClothingShoesBootsJack eyes: ClothingEyesGlassesSecurity outerclothing: ClothingOuterCoatWarden - idcard: WardenPDA + id: WardenPDA ears: ClothingHeadsetSecurity belt: ClothingBeltSecurityFilled innerclothingskirt: ClothingUniformJumpskirtWarden