#nullable enable using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Utility; using Robust.Shared.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; using System; namespace Content.Shared.GameObjects.Components.Storage { /// /// Players can pick up, drop, and put items in bags, and they can be seen in player's hands. /// public abstract class SharedItemComponent : Component, IEquipped, IUnequipped, IInteractHand { public override string Name => "Item"; public override uint? NetID => ContentNetIDs.ITEM; /// /// How much big this item is. /// [ViewVariables(VVAccess.ReadWrite)] public int Size { get => _size; set { _size = value; Dirty(); } } [DataField("size")] private int _size; /// /// Part of the state of the sprite shown on the player when this item is in their hands. /// [ViewVariables(VVAccess.ReadWrite)] public string? EquippedPrefix { get => _equippedPrefix; set { _equippedPrefix = value; OnEquippedPrefixChange(); Dirty(); } } [DataField("HeldPrefix")] private string? _equippedPrefix; /// /// Color of the sprite shown on the player when this item is in their hands. /// [ViewVariables(VVAccess.ReadWrite)] public Color Color { get => _color; protected set { _color = value; Dirty(); } } [DataField("color")] private Color _color = Color.White; /// /// Rsi of the sprite shown on the player when this item is in their hands. /// [ViewVariables(VVAccess.ReadWrite)] public string? RsiPath { get => _rsiPath; set { _rsiPath = value; Dirty(); } } [DataField("sprite")] private string? _rsiPath; public override ComponentState GetComponentState(ICommonSession player) { 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. /// public bool CanPickup(IEntity user) { if (!ActionBlockerSystem.CanPickup(user)) return false; if (user.Transform.MapID != Owner.Transform.MapID) return false; if (!Owner.TryGetComponent(out IPhysBody? physics) || physics.BodyType == BodyType.Static) return false; return user.InRangeUnobstructed(Owner, ignoreInsideBlocker: true, popup: true); } void IEquipped.Equipped(EquippedEventArgs eventArgs) { EquippedToSlot(); } void IUnequipped.Unequipped(UnequippedEventArgs eventArgs) { RemovedFromSlot(); } bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { return TryPutInHand(eventArgs.User); } /// /// Tries to put this item in a player's hands. /// TODO: Move server implementation here once hands are in shared. /// public abstract bool TryPutInHand(IEntity user); protected virtual void OnEquippedPrefixChange() { } public virtual void RemovedFromSlot() { } public virtual void EquippedToSlot() { } } [Serializable, NetSerializable] public class ItemComponentState : ComponentState { public int Size { get; } public string? EquippedPrefix { get; } public Color Color { get; } public string? RsiPath { get; } public ItemComponentState(int size, string? equippedPrefix, Color color, string? rsiPath) : base(ContentNetIDs.ITEM) { Size = size; EquippedPrefix = equippedPrefix; Color = color; RsiPath = rsiPath; } } /// /// Reference sizes for common containers and items. /// public enum ReferenceSizes { Wallet = 4, Pocket = 12, Box = 24, Belt = 30, Toolbox = 60, Backpack = 100, NoStoring = 9999 } }