diff --git a/Content.Server/Storage/Components/ServerStorageComponent.cs b/Content.Server/Storage/Components/ServerStorageComponent.cs index 3a557b4e51..8c5014504f 100644 --- a/Content.Server/Storage/Components/ServerStorageComponent.cs +++ b/Content.Server/Storage/Components/ServerStorageComponent.cs @@ -71,6 +71,15 @@ namespace Content.Server.Storage.Components [DataField("whitelist")] private EntityWhitelist? _whitelist = null; + [DataField("blacklist")] + public EntityWhitelist? Blacklist = null; + + /// + /// If true, storage will show popup messages to the player after failed interactions. + /// Usually this is message that item doesn't fit inside container. + /// + [DataField("popup")] + public bool ShowPopup = true; private bool _storageInitialCalculated; public int StorageUsed; @@ -165,6 +174,11 @@ namespace Content.Server.Storage.Components return false; } + if (Blacklist != null && Blacklist.IsValid(entity)) + { + return false; + } + if (_entityManager.GetComponent(entity).Anchored) { return false; @@ -256,14 +270,14 @@ namespace Content.Server.Storage.Components if (!handSys.TryDrop(player, toInsert.Value, handsComp: hands)) { - Owner.PopupMessage(player, Loc.GetString("comp-storage-cant-insert")); + Popup(player, "comp-storage-cant-insert"); return false; } if (!Insert(toInsert.Value)) { handSys.PickupOrDrop(player, toInsert.Value, handsComp: hands); - Owner.PopupMessage(player, Loc.GetString("comp-storage-cant-insert")); + Popup(player, "comp-storage-cant-insert"); return false; } @@ -282,7 +296,7 @@ namespace Content.Server.Storage.Components if (!Insert(toInsert)) { - Owner.PopupMessage(player, Loc.GetString("comp-storage-cant-insert")); + Popup(player, "comp-storage-cant-insert"); return false; } return true; @@ -482,7 +496,7 @@ namespace Content.Server.Storage.Components return; } - if (!EntitySystem.Get().InRangeUnobstructed(player, Owner, popup: true)) + if (!EntitySystem.Get().InRangeUnobstructed(player, Owner, popup: ShowPopup)) { return; } @@ -638,6 +652,13 @@ namespace Content.Server.Storage.Components } } + private void Popup(EntityUid player, string message) + { + if (!ShowPopup) return; + + Owner.PopupMessage(player, Loc.GetString(message)); + } + private void PlaySoundCollection() { SoundSystem.Play(Filter.Pvs(Owner), StorageSoundCollection.GetSound(), Owner, AudioParams.Default); diff --git a/Content.Server/Storage/EntitySystems/ItemMapperSystem.cs b/Content.Server/Storage/EntitySystems/ItemMapperSystem.cs index 46d17fca1b..12344a1e25 100644 --- a/Content.Server/Storage/EntitySystems/ItemMapperSystem.cs +++ b/Content.Server/Storage/EntitySystems/ItemMapperSystem.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Linq; using Content.Server.Storage.Components; using Content.Shared.Storage.Components; using Content.Shared.Storage.EntitySystems; @@ -12,32 +13,27 @@ namespace Content.Server.Storage.EntitySystems [UsedImplicitly] public sealed class ItemMapperSystem : SharedItemMapperSystem { + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + protected override bool TryGetLayers(ContainerModifiedMessage msg, ItemMapperComponent itemMapper, out IReadOnlyList showLayers) { - if (EntityManager.TryGetComponent(msg.Container.Owner, out ServerStorageComponent? component)) - { - var containedLayers = component.StoredEntities ?? new List(); - var list = new List(); - foreach (var mapLayerData in itemMapper.MapLayers.Values) - { - foreach (var entity in containedLayers) - { - if (mapLayerData.ServerWhitelist.IsValid(entity)) - { - list.Add(mapLayerData.Layer); - break; - } - } - } + var containedLayers = _containerSystem.GetAllContainers(msg.Container.Owner) + .SelectMany(cont => cont.ContainedEntities).ToArray(); - showLayers = list; - return true; + var list = new List(); + foreach (var mapLayerData in itemMapper.MapLayers.Values) + { + var count = containedLayers.Count(uid => mapLayerData.ServerWhitelist.IsValid(uid)); + if (count >= mapLayerData.MinCount && count <= mapLayerData.MaxCount) + { + list.Add(mapLayerData.Layer); + } } - showLayers = new List(); - return false; + showLayers = list; + return true; } } } diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs index 0c193be5f7..ebe5971dd3 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs @@ -116,6 +116,13 @@ namespace Content.Shared.Containers.ItemSlots [ViewVariables(VVAccess.ReadWrite)] public bool Locked = false; + /// + /// Whether the item slots system will attempt to insert item from the user's hands into this slot when interacted with. + /// It doesn't block other insertion methods, like verbs. + /// + [DataField("insertOnInteract")] + public bool InsertOnInteract = true; + /// /// Whether the item slots system will attempt to eject this item to the user's hands when interacted with. /// diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index 65c051dff4..bf461be347 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -170,6 +170,9 @@ namespace Content.Shared.Containers.ItemSlots foreach (var slot in itemSlots.Slots.Values) { + if (!slot.InsertOnInteract) + continue; + if (!CanInsert(uid, args.Used, slot, swap: slot.Swap, popup: args.User)) continue; diff --git a/Content.Shared/Storage/Components/SharedMapLayerData.cs b/Content.Shared/Storage/Components/SharedMapLayerData.cs index 048e0b02ce..604b106cb3 100644 --- a/Content.Shared/Storage/Components/SharedMapLayerData.cs +++ b/Content.Shared/Storage/Components/SharedMapLayerData.cs @@ -21,6 +21,20 @@ namespace Content.Shared.Storage.Components [DataField("whitelist", required: true, serverOnly: true)] public EntityWhitelist ServerWhitelist { get; set; } = new(); + + /// + /// Minimal amount of entities that are valid for whitelist. + /// If it's smaller than minimal amount, layer will be hidden. + /// + [DataField("minCount")] + public int MinCount = 1; + + /// + /// Max amount of entities that are valid for whitelist. + /// If it's bigger than max amount, layer will be hidden. + /// + [DataField("maxCount")] + public int MaxCount = int.MaxValue; } [Serializable, NetSerializable] diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index a31456d265..0666af8233 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -9,7 +9,7 @@ sprite: Objects/Specific/Janitorial/mop.rsi state: mop - type: Item - size: 10 + size: 15 sprite: Objects/Specific/Janitorial/mop.rsi - type: Absorbent - type: SolutionContainerManager @@ -74,3 +74,129 @@ state: caution - type: Item sprite: Objects/Specific/Janitorial/wet_floor_sign.rsi + size: 15 + - type: Tag + tags: + - WetFloorSign + +- type: entity + name: janitorial trolley + id: JanitorialTrolley + parent: BaseStructureDynamic + description: This is the alpha and omega of sanitation. + components: + - type: Sprite + netSync: false + noRot: true + sprite: Objects/Specific/Janitorial/janitorial_cart.rsi + layers: + - state: cart + - state: cart_water_1 + map: ["enum.SolutionContainerLayers.Fill"] + - type: Rotatable + - type: InteractionOutline + - type: Storage + popup: false + capacity: 80 + blacklist: # there is exclusive item slots for that + tags: + - Mop + - TrashBag + - type: ItemSlots + slots: + mop_slot: + name: Mop + whitelist: + tags: + - Mop + insertOnInteract: false # or it conflicts with bucket logic + trashbag_slot: + name: Bag + whitelist: + tags: + - TrashBag + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.3 + layer: + - SmallImpassable + mask: + - VaultImpassable + mass: 100 + - type: SolutionContainerManager + solutions: + bucket: + maxVol: 500 + reagents: + - ReagentId: Water + Quantity: 250 # half-full at roundstart to leave room for puddles + - type: DrainableSolution + solution: bucket + - type: RefillableSolution + solution: bucket + - type: Tag + tags: + - Wringer + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 200 + behaviors: + - !type:EmptyAllContainersBehaviour + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - type: ItemMapper + mapLayers: + cart_mop: + whitelist: + tags: + - Mop + cart_garbage: + whitelist: + tags: + - TrashBag + cart_replacer: + whitelist: + components: + - LightReplacer + cart_spray: + whitelist: + tags: + - Spray + cart_sign1: # this is like stack of floor signs + minCount: 1 + whitelist: + tags: + - WetFloorSign + cart_sign2: + minCount: 2 + whitelist: + tags: + - WetFloorSign + cart_sign3: + minCount: 3 + whitelist: + tags: + - WetFloorSign + cart_sign4: + minCount: 4 + whitelist: + tags: + - WetFloorSign + - type: Appearance + visuals: + - type: MappedItemVisualizer + sprite: Objects/Specific/Janitorial/janitorial_cart.rsi + - type: SolutionContainerVisualizer + maxFillLevels: 3 + fillBaseName: cart_water_ + changeColor: false diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index faa02344d3..75c37ff665 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -298,6 +298,9 @@ - type: Tag id: TrashBag +- type: Tag + id: WetFloorSign + - type: Tag id: Wall diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart.png new file mode 100644 index 0000000000..240bb4a061 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_garbage.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_garbage.png new file mode 100644 index 0000000000..bc8abf100f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_garbage.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_mop.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_mop.png new file mode 100644 index 0000000000..4e08a5e388 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_mop.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_replacer.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_replacer.png new file mode 100644 index 0000000000..c0b0d6c397 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_replacer.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign1.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign1.png new file mode 100644 index 0000000000..0af6aa459d Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign1.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign2.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign2.png new file mode 100644 index 0000000000..0eb81e760f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign2.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign3.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign3.png new file mode 100644 index 0000000000..be6dbff973 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign3.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign4.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign4.png new file mode 100644 index 0000000000..5c749d4b0e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_sign4.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_spray.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_spray.png new file mode 100644 index 0000000000..62af7e9836 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_spray.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_1.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_1.png new file mode 100644 index 0000000000..371b6ccfb5 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_1.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_2.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_2.png new file mode 100644 index 0000000000..153808e017 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_2.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_3.png b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_3.png new file mode 100644 index 0000000000..20298c57b0 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/cart_water_3.png differ diff --git a/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/meta.json b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/meta.json new file mode 100644 index 0000000000..5d2fd5515d --- /dev/null +++ b/Resources/Textures/Objects/Specific/Janitorial/janitorial_cart.rsi/meta.json @@ -0,0 +1,125 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/f8f4aeda930fcd0805ca4cc76d9bc9412a5b3428", + "states": [ + { + "name": "cart", + "directions": 4 + }, + { + "name": "cart_garbage", + "directions": 4 + }, + { + "name": "cart_mop", + "directions": 4 + }, + { + "name": "cart_replacer", + "directions": 4 + }, + { + "name": "cart_sign1", + "directions": 4 + }, + { + "name": "cart_sign2", + "directions": 4 + }, + { + "name": "cart_sign3", + "directions": 4 + }, + { + "name": "cart_sign4", + "directions": 4 + }, + { + "name": "cart_spray", + "directions": 4 + }, + { + "name": "cart_water_1", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "cart_water_2", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "cart_water_3", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} \ No newline at end of file