using Content.Shared.Item; using Content.Shared.Storage.EntitySystems; using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Storage { /// /// Handles generic storage with window, such as backpacks. /// [RegisterComponent, NetworkedComponent] public sealed partial class StorageComponent : Component { public static string ContainerId = "storagebase"; [ViewVariables] public Container Container = default!; /// /// A dictionary storing each entity to its position within the storage grid. /// [DataField, ViewVariables(VVAccess.ReadWrite)] public Dictionary StoredItems = new(); /// /// A dictionary storing each saved item to its location in the grid. /// When trying to quick insert an item, if there is an empty location with the same name it will be placed there. /// Multiple items with the same name can be saved, they will be checked individually. /// [DataField] public Dictionary> SavedLocations = new(); /// /// A list of boxes that comprise a combined grid that determines the location that items can be stored. /// [DataField, ViewVariables(VVAccess.ReadWrite)] public List Grid = new(); /// /// The maximum size item that can be inserted into this storage, /// [DataField, ViewVariables(VVAccess.ReadWrite)] [Access(typeof(SharedStorageSystem))] public ProtoId? MaxItemSize; // TODO: Make area insert its own component. [DataField] public bool QuickInsert; // Can insert storables by clicking them with the storage entity /// /// Minimum delay between quick/area insert actions. /// /// Used to prevent autoclickers spamming server with individual pickup actions. public TimeSpan QuickInsertCooldown = TimeSpan.FromSeconds(0.5); /// /// Minimum delay between UI open actions. /// Used to spamming opening sounds. /// [DataField] public TimeSpan OpenUiCooldown = TimeSpan.Zero; /// /// Can insert stuff by clicking the storage entity with it. /// [DataField] public bool ClickInsert = true; /// /// Open the storage window when pressing E. /// When false you can still open the inventory using verbs. /// [DataField] public bool OpenOnActivate = true; /// /// How many entities area pickup can pickup at once. /// public const int AreaPickupLimit = 10; [DataField] public bool AreaInsert; // Clicking with the storage entity causes it to insert all nearby storables after a delay [DataField] public int AreaInsertRadius = 1; /// /// Whitelist for entities that can go into the storage. /// [DataField] public EntityWhitelist? Whitelist; /// /// Blacklist for entities that can go into storage. /// [DataField] public EntityWhitelist? Blacklist; /// /// Sound played whenever an entity is inserted into storage. /// [DataField] public SoundSpecifier? StorageInsertSound = new SoundCollectionSpecifier("storageRustle"); /// /// Sound played whenever an entity is removed from storage. /// [DataField] public SoundSpecifier? StorageRemoveSound; /// /// Sound played whenever the storage window is opened. /// [DataField] public SoundSpecifier? StorageOpenSound = new SoundCollectionSpecifier("storageRustle"); /// /// Sound played whenever the storage window is closed. /// [DataField] public SoundSpecifier? StorageCloseSound; /// /// If not null, ensures that all inserted items are of the same orientation /// Horizontal - items are stored laying down /// Vertical - items are stored standing up /// [DataField, ViewVariables(VVAccess.ReadWrite)] public StorageDefaultOrientation? DefaultStorageOrientation; /// /// If true, sets StackVisuals.Hide to true when the container is closed /// Used in cases where there are sprites that are shown when the container is open but not /// when it is closed /// [DataField] public bool HideStackVisualsWhenClosed = true; [Serializable, NetSerializable] public enum StorageUiKey : byte { Key, } } [Serializable, NetSerializable] public sealed class OpenNestedStorageEvent : EntityEventArgs { public readonly NetEntity InteractedItemUid; public readonly NetEntity StorageUid; public OpenNestedStorageEvent(NetEntity interactedItemUid, NetEntity storageUid) { InteractedItemUid = interactedItemUid; StorageUid = storageUid; } } [Serializable, NetSerializable] public sealed class StorageInteractWithItemEvent : EntityEventArgs { public readonly NetEntity InteractedItemUid; public readonly NetEntity StorageUid; public StorageInteractWithItemEvent(NetEntity interactedItemUid, NetEntity storageUid) { InteractedItemUid = interactedItemUid; StorageUid = storageUid; } } [Serializable, NetSerializable] public sealed class StorageSetItemLocationEvent : EntityEventArgs { public readonly NetEntity ItemEnt; public readonly NetEntity StorageEnt; public readonly ItemStorageLocation Location; public StorageSetItemLocationEvent(NetEntity itemEnt, NetEntity storageEnt, ItemStorageLocation location) { ItemEnt = itemEnt; StorageEnt = storageEnt; Location = location; } } [Serializable, NetSerializable] public sealed class StorageTransferItemEvent : EntityEventArgs { public readonly NetEntity ItemEnt; /// /// Target storage to receive the transfer. /// public readonly NetEntity StorageEnt; public readonly ItemStorageLocation Location; public StorageTransferItemEvent(NetEntity itemEnt, NetEntity storageEnt, ItemStorageLocation location) { ItemEnt = itemEnt; StorageEnt = storageEnt; Location = location; } } [Serializable, NetSerializable] public sealed class StorageInsertItemIntoLocationEvent : EntityEventArgs { public readonly NetEntity ItemEnt; public readonly NetEntity StorageEnt; public readonly ItemStorageLocation Location; public StorageInsertItemIntoLocationEvent(NetEntity itemEnt, NetEntity storageEnt, ItemStorageLocation location) { ItemEnt = itemEnt; StorageEnt = storageEnt; Location = location; } } [Serializable, NetSerializable] public sealed class StorageSaveItemLocationEvent : EntityEventArgs { public readonly NetEntity Item; public readonly NetEntity Storage; public StorageSaveItemLocationEvent(NetEntity item, NetEntity storage) { Item = item; Storage = storage; } } /// /// Network event for displaying an animation of entities flying into a storage entity /// [Serializable, NetSerializable] public sealed class AnimateInsertingEntitiesEvent : EntityEventArgs { public readonly NetEntity Storage; public readonly List StoredEntities; public readonly List EntityPositions; public readonly List EntityAngles; public AnimateInsertingEntitiesEvent(NetEntity storage, List storedEntities, List entityPositions, List entityAngles) { Storage = storage; StoredEntities = storedEntities; EntityPositions = entityPositions; EntityAngles = entityAngles; } } [ByRefEvent] public record struct StorageInteractAttemptEvent(bool Silent, bool Cancelled = false); [ByRefEvent] public record struct StorageInteractUsingAttemptEvent(bool Cancelled = false); [NetSerializable] [Serializable] public enum StorageVisuals : byte { Open, HasContents, StorageUsed, Capacity } [Serializable, NetSerializable] public enum StorageDefaultOrientation : byte { Horizontal, Vertical } }