diff --git a/Content.Server/_CorvaxNext/Storage/AnchorableStorageComponent.cs b/Content.Server/_CorvaxNext/Storage/AnchorableStorageComponent.cs new file mode 100644 index 00000000000..cf1a10fdc60 --- /dev/null +++ b/Content.Server/_CorvaxNext/Storage/AnchorableStorageComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Server._CorvaxNext.Storage; + +/// +/// This is used for restricting anchor operations on storage (one bag max per tile) +/// and ejecting sapient contents on anchor. +/// +[RegisterComponent] +public sealed partial class AnchorableStorageComponent : Component; \ No newline at end of file diff --git a/Content.Server/_CorvaxNext/Storage/AnchorableStorageSystem.cs b/Content.Server/_CorvaxNext/Storage/AnchorableStorageSystem.cs new file mode 100644 index 00000000000..b655f6c6124 --- /dev/null +++ b/Content.Server/_CorvaxNext/Storage/AnchorableStorageSystem.cs @@ -0,0 +1,99 @@ +using System.Linq; +using Content.Server.Popups; +using Content.Shared.Construction.Components; +using Content.Shared.Mind.Components; +using Content.Shared.Storage; +using Robust.Server.GameObjects; +using Robust.Shared.Containers; +using Robust.Shared.Map.Components; + +namespace Content.Server._CorvaxNext.Storage; + +/// +/// This is used for restricting anchor operations on storage (one bag max per tile) +/// and ejecting living contents on anchor. +/// +public sealed class AnchorableStorageSystem : EntitySystem +{ + [Dependency] private readonly MapSystem _map = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly TransformSystem _xform = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnAnchorStateChanged); + SubscribeLocalEvent(OnAnchorAttempt); + SubscribeLocalEvent(OnInsertAttempt); + } + + private void OnAnchorStateChanged(Entity ent, ref AnchorStateChangedEvent args) + { + if (!args.Anchored) + return; + + var transform = Transform(ent); + + if (CheckOverlap(ent, transform)) + { + _popup.PopupEntity(Loc.GetString("anchored-storage-already-present"), ent); + _xform.Unanchor(ent, transform); + return; + } + + if (!TryComp(ent.Owner, out var storage)) + return; + + foreach (var item in storage.StoredItems.Keys.ToArray()) + if (HasComp(item)) + _container.RemoveEntity(ent, item); + } + + private void OnAnchorAttempt(Entity ent, ref AnchorAttemptEvent args) + { + if (args.Cancelled) + return; + + if (!CheckOverlap(ent)) + return; + + _popup.PopupEntity(Loc.GetString("anchored-storage-already-present"), ent, args.User); + args.Cancel(); + } + + private void OnInsertAttempt(Entity ent, ref ContainerIsInsertingAttemptEvent args) + { + if (args.Cancelled) + return; + + if (!HasComp(args.EntityUid)) + return; + + if (Transform(ent).Anchored) + args.Cancel(); + } + + public bool CheckOverlap(EntityUid entity, TransformComponent? transform = null) + { + if (!Resolve(entity, ref transform)) + return false; + + if (transform.GridUid is not { } grid || !TryComp(grid, out var gridComp)) + return false; + + var indices = _map.TileIndicesFor(grid, gridComp, transform.Coordinates); + var enumerator = _map.GetAnchoredEntitiesEnumerator(grid, gridComp, indices); + + while (enumerator.MoveNext(out var otherEnt)) + { + if (otherEnt == entity) + continue; + + if (HasComp(otherEnt)) + return true; + } + + return false; + } +} diff --git a/Resources/Locale/en-US/_corvaxnext/storage/anchorable-storage.ftl b/Resources/Locale/en-US/_corvaxnext/storage/anchorable-storage.ftl new file mode 100644 index 00000000000..1eea4cc9a2e --- /dev/null +++ b/Resources/Locale/en-US/_corvaxnext/storage/anchorable-storage.ftl @@ -0,0 +1 @@ +anchored-storage-already-present = There's already a bag anchored here! \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_corvaxnext/storage/anchorable-storage.ftl b/Resources/Locale/ru-RU/_corvaxnext/storage/anchorable-storage.ftl new file mode 100644 index 00000000000..5f089cb438f --- /dev/null +++ b/Resources/Locale/ru-RU/_corvaxnext/storage/anchorable-storage.ftl @@ -0,0 +1 @@ +anchored-storage-already-present = Здесь уже что-то спрятано! \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml index ee7d9904269..764a21f6e07 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml @@ -16,3 +16,4 @@ ClothingHandsGlovesColorBlack: 2 ClothingHandsGlovesLatex: 2 ClothingHeadsetSecurity: 2 + trayScanner: 2 # Corvax-Next-Stashes diff --git a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml index b589b2bbc08..90fdf3fdf27 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml @@ -30,6 +30,16 @@ delay: 0.5 - type: ExplosionResistance damageCoefficient: 0.9 + # Corvax-Next-Stashes-Start + - type: Appearance + - type: SubFloorHide + - type: Anchorable + - type: CollideOnAnchor + enable: false + - type: Transform + anchored: false + - type: AnchorableStorage + # Corvax-Next-Stashes-End - type: entity parent: ClothingBackpack