diff --git a/Content.Shared/Foldable/FoldableSystem.cs b/Content.Shared/Foldable/FoldableSystem.cs index 2a846f4f23..c251372372 100644 --- a/Content.Shared/Foldable/FoldableSystem.cs +++ b/Content.Shared/Foldable/FoldableSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Body.Components; using Content.Shared.Buckle; using Content.Shared.Buckle.Components; using Content.Shared.Storage.Components; @@ -23,7 +24,7 @@ public sealed class FoldableSystem : EntitySystem SubscribeLocalEvent(OnFoldableInit); SubscribeLocalEvent(OnInsertEvent); - SubscribeLocalEvent(OnStoreThisAttempt); + SubscribeLocalEvent(OnStoreThisAttempt); SubscribeLocalEvent(OnFoldableOpenAttempt); SubscribeLocalEvent(OnStrapAttempt); @@ -45,10 +46,8 @@ public sealed class FoldableSystem : EntitySystem args.Cancelled = true; } - public void OnStoreThisAttempt(EntityUid uid, FoldableComponent comp, ref StoreMobInItemContainerAttemptEvent args) + public void OnStoreThisAttempt(EntityUid uid, FoldableComponent comp, ref InsertIntoEntityStorageAttemptEvent args) { - args.Handled = true; - if (comp.IsFolded) args.Cancelled = true; } diff --git a/Content.Shared/Storage/Components/SharedEntityStorageComponent.cs b/Content.Shared/Storage/Components/SharedEntityStorageComponent.cs index b02c97db71..4100449f4e 100644 --- a/Content.Shared/Storage/Components/SharedEntityStorageComponent.cs +++ b/Content.Shared/Storage/Components/SharedEntityStorageComponent.cs @@ -64,12 +64,6 @@ public abstract partial class SharedEntityStorageComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public float EnteringRange = 0.18f; - /// - /// If true, there may be mobs inside the container, even if the container is an Item - /// - [DataField] - public bool ItemCanStoreMobs = false; - /// /// Whether or not to show the contents when the storage is closed /// @@ -153,10 +147,7 @@ public sealed class EntityStorageComponentState : ComponentState } [ByRefEvent] -public record struct InsertIntoEntityStorageAttemptEvent(bool Cancelled = false); - -[ByRefEvent] -public record struct StoreMobInItemContainerAttemptEvent(bool Handled, bool Cancelled = false); +public record struct InsertIntoEntityStorageAttemptEvent(EntityUid ItemToInsert, bool Cancelled = false); [ByRefEvent] public record struct StorageOpenAttemptEvent(EntityUid User, bool Silent, bool Cancelled = false); diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 52e2fb68d8..abd08c7459 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -241,26 +241,27 @@ public abstract class SharedEntityStorageSystem : EntitySystem component.Open = false; Dirty(uid, component); - var targetCoordinates = new EntityCoordinates(uid, component.EnteringOffset); + var entities = _lookup.GetEntitiesInRange( + new EntityCoordinates(uid, component.EnteringOffset), + component.EnteringRange, + LookupFlags.Approximate | LookupFlags.Dynamic | LookupFlags.Sundries + ); - var entities = _lookup.GetEntitiesInRange(targetCoordinates, component.EnteringRange, LookupFlags.Approximate | LookupFlags.Dynamic | LookupFlags.Sundries); + // Don't insert the container into itself. + entities.Remove(uid); - var ev = new StorageBeforeCloseEvent(entities, new()); + var ev = new StorageBeforeCloseEvent(entities, []); RaiseLocalEvent(uid, ref ev); - var count = 0; + foreach (var entity in ev.Contents) { - if (!ev.BypassChecks.Contains(entity)) - { - if (!CanInsert(entity, uid, component)) - continue; - } + if (!ev.BypassChecks.Contains(entity) && !CanInsert(entity, uid, component)) + continue; if (!AddToContents(entity, uid, component)) continue; - count++; - if (count >= component.Capacity) + if (component.Contents.ContainedEntities.Count >= component.Capacity) break; } @@ -331,7 +332,23 @@ public abstract class SharedEntityStorageSystem : EntitySystem if (component.Contents.ContainedEntities.Count >= component.Capacity) return false; - return CanFit(toInsert, container, component); + var aabb = _lookup.GetAABBNoContainer(toInsert, Vector2.Zero, 0); + if (component.MaxSize < aabb.Size.X || component.MaxSize < aabb.Size.Y) + return false; + + // Allow other systems to prevent inserting the item: e.g. the item is actually a ghost. + var attemptEvent = new InsertIntoEntityStorageAttemptEvent(toInsert); + RaiseLocalEvent(toInsert, ref attemptEvent); + + if (attemptEvent.Cancelled) + return false; + + // Consult the whitelist. The whitelist ignores the default assumption about how entity storage works. + if (component.Whitelist != null) + return _whitelistSystem.IsValid(component.Whitelist, toInsert); + + // The inserted entity must be a mob or an item. + return HasComp(toInsert) || HasComp(toInsert); } public bool TryOpenStorage(EntityUid user, EntityUid target, bool silent = false) @@ -412,60 +429,9 @@ public abstract class SharedEntityStorageSystem : EntitySystem if (toAdd == container) return false; - var aabb = _lookup.GetAABBNoContainer(toAdd, Vector2.Zero, 0); - if (component.MaxSize < aabb.Size.X || component.MaxSize < aabb.Size.Y) - return false; - return Insert(toAdd, container, component); } - private bool CanFit(EntityUid toInsert, EntityUid container, SharedEntityStorageComponent? component = null) - { - if (!Resolve(container, ref component)) - return false; - - // conditions are complicated because of pizzabox-related issues, so follow this guide - // 0. Accomplish your goals at all costs. - // 1. AddToContents can block anything - // 2. maximum item count can block anything - // 3. ghosts can NEVER be eaten - // 4. items can always be eaten unless a previous law prevents it - // 5. if this is NOT AN ITEM, then mobs can always be eaten unless a previous - // law prevents it - // 6. if this is an item, then mobs must only be eaten if some other component prevents - // pick-up interactions while a mob is inside (e.g. foldable) - var attemptEvent = new InsertIntoEntityStorageAttemptEvent(); - RaiseLocalEvent(toInsert, ref attemptEvent); - if (attemptEvent.Cancelled) - return false; - - var targetIsMob = HasComp(toInsert); - var storageIsItem = HasComp(container); - var allowedToEat = component.Whitelist == null ? HasComp(toInsert) : _whitelistSystem.IsValid(component.Whitelist, toInsert); - - // BEFORE REPLACING THIS WITH, I.E. A PROPERTY: - // Make absolutely 100% sure you have worked out how to stop people ending up in backpacks. - // Seriously, it is insanely hacky and weird to get someone out of a backpack once they end up in there. - // And to be clear, they should NOT be in there. - // For the record, what you need to do is empty the backpack onto a PlacableSurface (table, rack) - if (targetIsMob) - { - if (!storageIsItem) - allowedToEat = true; - else - { - var storeEv = new StoreMobInItemContainerAttemptEvent(); - RaiseLocalEvent(container, ref storeEv); - allowedToEat = storeEv is { Handled: true, Cancelled: false }; - - if (component.ItemCanStoreMobs) - allowedToEat = true; - } - } - - return allowedToEat; - } - private void ModifyComponents(EntityUid uid, SharedEntityStorageComponent? component = null) { if (!ResolveStorage(uid, ref component)) diff --git a/Resources/Prototypes/Entities/Objects/Misc/arabianlamp.yml b/Resources/Prototypes/Entities/Objects/Misc/arabianlamp.yml index ee40316e62..844db3f765 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/arabianlamp.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/arabianlamp.yml @@ -13,7 +13,6 @@ breakOnAccessBreaker: false - type: EntityStorage capacity: 1 # Its smol. - itemCanStoreMobs: false # just leaving this here explicitly since I know at some point someone will want to use this to hold a mob. This also prevents it from becoming His Grace. # - type: StorageFill # contents: # - id: PuddleSparkle # Ha! Cute. Unfortunately it despawns before the container is likely to open. diff --git a/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml b/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml index 725db6731f..4ae684c193 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml @@ -1,7 +1,7 @@ - type: entity id: PetCarrier name: big pet carrier - description: Allows large animals to be carried comfortably. + description: Allows large animals to be carried comfortably. It smells vaguely of toilet water and explosives. parent: BaseStructureDynamic components: - type: Sprite @@ -36,7 +36,9 @@ - type: EntityStorage capacity: 1 airtight: false - itemCanStoreMobs: true + whitelist: + tags: + - VimPilot # If it can fit in a Vim it can fit in a pet carrier. - type: Weldable - type: ResistLocker - type: PlaceableSurface diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml index 6c42b8f59f..32f997d50f 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml @@ -44,6 +44,10 @@ - type: EntityStorage capacity: 1 isCollidableWhenOpen: true + whitelist: # Use a tag whitelist rather than filtering for PerishableComponent to avoid chefs using body bags for food preservation + tags: + - VimPilot # Pets + - CanPilot # People closeSound: path: /Audio/Misc/zip.ogg openSound: diff --git a/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml b/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml index 7d1719a708..b9efefdf75 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml @@ -128,6 +128,9 @@ whitelist: components: - Artifact + tags: + - CanPilot # People + - VimPilot # Pets - type: Appearance - type: GenericVisualizer visuals: