diff --git a/Content.Shared/Clothing/Components/EmitsSoundOnMoveComponent.cs b/Content.Shared/Clothing/Components/EmitsSoundOnMoveComponent.cs
new file mode 100644
index 0000000000..095b0daf38
--- /dev/null
+++ b/Content.Shared/Clothing/Components/EmitsSoundOnMoveComponent.cs
@@ -0,0 +1,35 @@
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Map;
+
+namespace Content.Shared.Clothing.Components;
+
+///
+/// Indicates that the clothing entity emits sound when it moves.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class EmitsSoundOnMoveComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField(required: true), AutoNetworkedField]
+ public SoundSpecifier SoundCollection = default!;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("requiresGravity"), AutoNetworkedField]
+ public bool RequiresGravity = true;
+
+ [ViewVariables(VVAccess.ReadOnly)]
+ public EntityCoordinates LastPosition = EntityCoordinates.Invalid;
+
+ ///
+ /// The distance moved since the played sound.
+ ///
+ [ViewVariables(VVAccess.ReadOnly)]
+ public float SoundDistance = 0f;
+
+ ///
+ /// Whether this item is equipped in a inventory item slot.
+ ///
+ [ViewVariables(VVAccess.ReadOnly)]
+ public bool IsSlotValid = true;
+}
diff --git a/Content.Shared/Clothing/EntitySystems/EmitsSoundOnMoveSystem.cs b/Content.Shared/Clothing/EntitySystems/EmitsSoundOnMoveSystem.cs
new file mode 100644
index 0000000000..3224b5bca3
--- /dev/null
+++ b/Content.Shared/Clothing/EntitySystems/EmitsSoundOnMoveSystem.cs
@@ -0,0 +1,96 @@
+using System.Numerics;
+using Content.Shared.Clothing.Components;
+using Content.Shared.Gravity;
+using Content.Shared.Inventory;
+using Content.Shared.Inventory.Events;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Movement.Components;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Clothing.Systems;
+
+public sealed class EmitsSoundOnMoveSystem : EntitySystem
+{
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedMapSystem _grid = default!;
+ [Dependency] private readonly SharedGravitySystem _gravity = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ private EntityQuery _moverQuery;
+ private EntityQuery _physicsQuery;
+ private EntityQuery _clothingQuery;
+
+ public override void Initialize()
+ {
+ _moverQuery = GetEntityQuery();
+ _physicsQuery = GetEntityQuery();
+ _clothingQuery = GetEntityQuery();
+
+ SubscribeLocalEvent(OnEquipped);
+ SubscribeLocalEvent(OnUnequipped);
+ }
+
+ private void OnEquipped(EntityUid uid, EmitsSoundOnMoveComponent component, GotEquippedEvent args)
+ {
+ component.IsSlotValid = !args.SlotFlags.HasFlag(SlotFlags.POCKET);
+ }
+
+ private void OnUnequipped(EntityUid uid, EmitsSoundOnMoveComponent component, GotUnequippedEvent args)
+ {
+ component.IsSlotValid = true;
+ }
+
+ public override void Update(float frameTime)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var comp))
+ {
+ UpdateSound(uid, comp);
+ }
+ query.Dispose();
+ }
+
+ private void UpdateSound(EntityUid uid, EmitsSoundOnMoveComponent component)
+ {
+ if (!_physicsQuery.TryGetComponent(uid, out var physics))
+ return;
+
+ // Space does not transmit sound
+ if (Transform(uid).GridUid == null)
+ return;
+
+ if (component.RequiresGravity && _gravity.IsWeightless(uid, physics, Transform(uid)))
+ return;
+
+ var parent = Transform(uid).ParentUid;
+
+ var isWorn = parent is { Valid: true } &&
+ _clothingQuery.TryGetComponent(uid, out var clothing)
+ && clothing.InSlot != null
+ && component.IsSlotValid;
+ // If this entity is worn by another entity, use that entity's coordinates
+ var coordinates = isWorn ? Transform(parent).Coordinates : Transform(uid).Coordinates;
+ var distanceNeeded = (isWorn && _moverQuery.TryGetComponent(parent, out var mover) && mover.Sprinting)
+ ? 1.5f // The parent is a mob that is currently sprinting
+ : 2f; // The parent is not a mob or is not sprinting
+
+ if (!coordinates.TryDistance(EntityManager, component.LastPosition, out var distance) || distance > distanceNeeded)
+ component.SoundDistance = distanceNeeded;
+ else
+ component.SoundDistance += distance;
+
+ component.LastPosition = coordinates;
+ if (component.SoundDistance < distanceNeeded)
+ return;
+ component.SoundDistance -= distanceNeeded;
+
+ var sound = component.SoundCollection;
+ var audioParams = sound.Params
+ .WithVolume(sound.Params.Volume)
+ .WithVariation(sound.Params.Variation ?? 0f);
+
+ _audio.PlayPredicted(sound, uid, uid, audioParams);
+ }
+}
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml
index 6d387eb877..97dd0eafa6 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml
@@ -89,6 +89,7 @@
ClothingHandsGlovesColorPurple: 2
ClothingEyesGlassesCheapSunglasses: 3
# DO NOT ADD MORE, USE UNIFORM DYING
+ ClothingClothWrap: 4
contrabandInventory:
ClothingMaskNeckGaiter: 2
ClothingUniformJumpsuitTacticool: 1
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml
index 8ef72f557c..348eab7f05 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml
@@ -56,6 +56,8 @@
ClothingShoesBootsCowboyBlack: 1
ClothingShoesBootsCowboyWhite: 1
ClothingMaskNeckGaiterRed: 2
+ ClothingNeckBellCollar: 2
+ ClothingOuterUnathiRobe: 1
emaggedInventory:
ClothingShoesBling: 1
ClothingShoesBootsCowboyFancy: 1
diff --git a/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml b/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml
index 6844177d77..f6caae659d 100644
--- a/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml
+++ b/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml
@@ -85,3 +85,25 @@
sprite: Clothing/Neck/mantles/mantle.rsi
- type: Clothing
sprite: Clothing/Neck/mantles/mantle.rsi
+
+- type: entity
+ parent: ClothingNeckBase
+ id: ClothingNeckOldMantle
+ name: old wrap
+ description: A tattered fabric wrap, faded over the years. Smells faintly of cigars.
+ components:
+ - type: Sprite
+ sprite: Clothing/Neck/mantles/oldmantle.rsi
+ - type: Clothing
+ sprite: Clothing/Neck/mantles/oldmantle.rsi
+
+- type: entity
+ parent: ClothingNeckBase
+ id: ClothingNeckUnathiMantle
+ name: hide mantle
+ description: A rather grisly selection of cured hides and skin, sewn together to form a ragged mantle.
+ components:
+ - type: Sprite
+ sprite: Clothing/Neck/mantles/unathimantle.rsi
+ - type: Clothing
+ sprite: Clothing/Neck/mantles/unathimantle.rsi
diff --git a/Resources/Prototypes/Entities/Clothing/Neck/misc.yml b/Resources/Prototypes/Entities/Clothing/Neck/misc.yml
index 8dfc709bc4..63a9ff3fb9 100644
--- a/Resources/Prototypes/Entities/Clothing/Neck/misc.yml
+++ b/Resources/Prototypes/Entities/Clothing/Neck/misc.yml
@@ -78,3 +78,17 @@
event: !type:StethoscopeActionEvent
checkCanInteract: false
priority: -1
+
+- type: entity
+ parent: ClothingNeckBase
+ id: ClothingNeckBellCollar
+ name: bell collar
+ description: A way to inform others about your presence, or just to annoy everyone around you!
+ components:
+ - type: Sprite
+ sprite: Clothing/Neck/Misc/bellcollar.rsi
+ - type: Clothing
+ sprite: Clothing/Neck/Misc/bellcollar.rsi
+ - type: EmitsSoundOnMove
+ soundCollection:
+ collection: FootstepJester
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml
index 112637cdd3..0b5e2c112b 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml
@@ -384,3 +384,14 @@
sprite: Clothing/OuterClothing/Misc/red_racoon.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Misc/red_racoon.rsi
+
+- type: entity
+ parent: ClothingOuterBase
+ id: ClothingOuterUnathiRobe
+ name: roughspun robes
+ description: A traditional Unathi garment.
+ components:
+ - type: Sprite
+ sprite: Clothing/OuterClothing/Misc/unathirobe.rsi
+ - type: Clothing
+ sprite: Clothing/OuterClothing/Misc/unathirobe.rsi
diff --git a/Resources/Prototypes/Entities/Clothing/clothwarps.yml b/Resources/Prototypes/Entities/Clothing/clothwarps.yml
new file mode 100644
index 0000000000..eadeaa0b28
--- /dev/null
+++ b/Resources/Prototypes/Entities/Clothing/clothwarps.yml
@@ -0,0 +1,38 @@
+- type: entity
+ parent: Clothing
+ id: ClothingClothWrap
+ name: cloth wraps
+ description: A roll of treated canvas used for wrapping claws or paws.
+ components:
+ - type: Item
+ size: Small
+ storedRotation: -90
+ - type: Sprite
+ state: icon
+ sprite: Clothing/Shoes/Misc/clothWrap.rsi
+ - type: Clothing
+ slots:
+ - gloves
+ - FEET
+ sprite: Clothing/Shoes/Misc/clothWrap.rsi
+ - type: Construction
+ graph: ClothingClothWrap
+ node: shoes
+ - type: Butcherable
+ butcheringType: Knife
+ spawned:
+ - id: MaterialCloth1
+ amount: 1
+ - type: Food
+ requiresSpecialDigestion: true
+ - type: SolutionContainerManager
+ solutions:
+ food:
+ maxVol: 10
+ reagents:
+ - ReagentId: Fiber
+ Quantity: 10
+ - type: Tag
+ tags:
+ - ClothMade
+ - WhitelistChameleon
diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/clothing/clothwarp.yml b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/clothwarp.yml
new file mode 100644
index 0000000000..864d8f18d2
--- /dev/null
+++ b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/clothwarp.yml
@@ -0,0 +1,13 @@
+- type: constructionGraph
+ id: ClothingClothWrap
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: shoes
+ steps:
+ - material: Cloth
+ amount: 2
+ doAfter: 1
+ - node: shoes
+ entity: ClothingClothWrap
diff --git a/Resources/Prototypes/Recipes/Construction/clothing.yml b/Resources/Prototypes/Recipes/Construction/clothing.yml
index 420f38aab8..3ec11c36e0 100644
--- a/Resources/Prototypes/Recipes/Construction/clothing.yml
+++ b/Resources/Prototypes/Recipes/Construction/clothing.yml
@@ -118,3 +118,14 @@
description: Can hold up to 15 arrows, and fits snug around your waist.
icon: { sprite: Clothing/Belt/quiver.rsi, state: icon }
objectType: Item
+
+- type: construction
+ name: cloth wraps
+ id: ClothingClothWrap
+ graph: ClothingClothWrap
+ startNode: start
+ targetNode: shoes
+ category: construction-category-clothing
+ description: A roll of treated canvas used for wrapping claws or paws.
+ icon: { sprite: Clothing/Shoes/Misc/clothWrap.rsi, state: icon }
+ objectType: Item
diff --git a/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/equipped-NECK.png b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/equipped-NECK.png
new file mode 100644
index 0000000000..2190dc844d
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/equipped-NECK.png differ
diff --git a/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/icon.png b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/icon.png
new file mode 100644
index 0000000000..1790484039
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/inhand-left.png b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/inhand-left.png
new file mode 100644
index 0000000000..2d727adbb2
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/inhand-left.png differ
diff --git a/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/inhand-right.png b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/inhand-right.png
new file mode 100644
index 0000000000..0e2c555c5c
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/inhand-right.png differ
diff --git a/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/meta.json b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/meta.json
new file mode 100644
index 0000000000..464e2e4a35
--- /dev/null
+++ b/Resources/Textures/Clothing/Neck/Misc/bellcollar.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Made by mnemotechnician (GitHub)",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-NECK",
+ "directions": 4
+ },
+ {
+ "name": "inhand-left",
+ "directions": 4
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/equipped-NECK.png b/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/equipped-NECK.png
new file mode 100644
index 0000000000..d317412c9d
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/equipped-NECK.png differ
diff --git a/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/icon.png b/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/icon.png
new file mode 100644
index 0000000000..4cf647611d
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/meta.json b/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/meta.json
new file mode 100644
index 0000000000..909b986cad
--- /dev/null
+++ b/Resources/Textures/Clothing/Neck/mantles/oldmantle.rsi/meta.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/ParadiseSS13/Paradise/blob/master/icons/mob/clothing/suit.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-NECK",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/equipped-NECK.png b/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/equipped-NECK.png
new file mode 100644
index 0000000000..5df12ac993
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/equipped-NECK.png differ
diff --git a/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/icon.png b/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/icon.png
new file mode 100644
index 0000000000..d59144a052
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/meta.json b/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/meta.json
new file mode 100644
index 0000000000..909b986cad
--- /dev/null
+++ b/Resources/Textures/Clothing/Neck/mantles/unathimantle.rsi/meta.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/ParadiseSS13/Paradise/blob/master/icons/mob/clothing/suit.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-NECK",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/equipped-OUTERCLOTHING.png
new file mode 100644
index 0000000000..f470372379
Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/equipped-OUTERCLOTHING.png differ
diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/icon.png
new file mode 100644
index 0000000000..54fd0c0741
Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/meta.json
new file mode 100644
index 0000000000..d66d07b5d5
--- /dev/null
+++ b/Resources/Textures/Clothing/OuterClothing/Misc/unathirobe.rsi/meta.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/ParadiseSS13/Paradise/blob/master/icons/mob/clothing/suit.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-OUTERCLOTHING",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/equipped-FEET.png b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/equipped-FEET.png
new file mode 100644
index 0000000000..4a3104fead
Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/equipped-FEET.png differ
diff --git a/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/equipped-HAND.png b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/equipped-HAND.png
new file mode 100644
index 0000000000..b78a810df8
Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/equipped-HAND.png differ
diff --git a/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/icon.png b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/icon.png
new file mode 100644
index 0000000000..8f531e890c
Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/meta.json
new file mode 100644
index 0000000000..02cbb7ef9a
--- /dev/null
+++ b/Resources/Textures/Clothing/Shoes/Misc/clothWrap.rsi/meta.json
@@ -0,0 +1,22 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/ParadiseSS13/Paradise/blob/master/icons/mob/clothing/feet.dmi / https://github.com/ParadiseSS13/Paradise/blob/master/icons/mob/clothing/hands.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-FEET",
+ "directions": 4
+ },
+ {
+ "name": "equipped-HAND",
+ "directions": 4
+ }
+ ]
+}