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..a8cbf09854 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml @@ -85,3 +85,102 @@ sprite: Clothing/Neck/mantles/mantle.rsi - type: Clothing sprite: Clothing/Neck/mantles/mantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleCap + name: captain's mantle + description: A comfortable and chique mantle befitting of only the most experienced captain. + components: + - type: Sprite + sprite: Clothing/Neck/mantles/capmantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/capmantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleCE + name: chief engineer's mantle + description: High visibility, check. RIG system, check. High capacity cell, check. Everything a chief engineer could need in a stylish mantle. + components: + - type: Sprite + sprite: Clothing/Neck/mantles/cemantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/cemantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleCMO + name: chief medical officer's mantle + description: For a CMO that has been in enough medbays to know that more PPE means less central command dry cleaning visits when the shift is over. + components: + - type: Sprite + sprite: Clothing/Neck/mantles/cmomantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/cmomantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleHOP + name: head of personnel's mantle + description: A good HOP knows that paper pushing is only half the job... petting your dog and looking fashionable is the other half. + components: + - type: Sprite + sprite: Clothing/Neck/mantles/hopmantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/hopmantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleHOS + name: head of security's mantle + description: Shootouts with nukies are just another Tuesday for this HoS. This mantle is a symbol of commitment to the station. + components: + - type: Sprite + sprite: Clothing/Neck/mantles/hosmantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/hosmantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleRD + name: mystagogue's mantle # DeltaV - Epistemics Department replacing Science + description: For when long days in the office consist of explosives, poisonous gas, murder robots, and a fresh pizza from logistics; this mantle will keep you comfy. # DeltaV - Logistics Department replacing Cargo + components: + - type: Sprite + sprite: Clothing/Neck/mantles/rdmantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/rdmantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleQM + name: logistics officer's mantle # DeltaV - Logistics Department replacing Cargo + description: For the master of goods and materials to rule over the department, a befitting mantle to show off superiority! + components: + - type: Sprite + sprite: Clothing/Neck/mantles/qmmantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/qmmantle.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 + } + ] +}