diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index 154171fc05..50a1d93a6c 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Tag; using Robust.Shared.GameStates; +using System.Linq; namespace Content.Shared.Clothing.EntitySystems; @@ -22,6 +23,9 @@ public abstract class ClothingSystem : EntitySystem [ValidatePrototypeId] private const string HairTag = "HidesHair"; + [ValidatePrototypeId] + private const string NoseTag = "HidesNose"; + public override void Initialize() { base.Initialize(); @@ -85,18 +89,57 @@ public abstract class ClothingSystem : EntitySystem } } + private void ToggleVisualLayer(EntityUid equipee, HumanoidVisualLayers layer, string tag) + { + InventorySystem.InventorySlotEnumerator enumerator = _invSystem.GetSlotEnumerator(equipee); + bool shouldLayerShow = true; + + while (enumerator.NextItem(out EntityUid item)) + { + if (_tagSystem.HasTag(item, tag)) + { + if (tag == NoseTag) //Special check needs to be made for NoseTag, due to masks being toggleable + { + if (TryComp(item, out MaskComponent? mask) && TryComp(item, out ClothingComponent? clothing)) + { + if (clothing.EquippedPrefix != mask.EquippedPrefix) + { + shouldLayerShow = false; + break; + } + } + else + { + shouldLayerShow = false; + break; + } + } + else + { + shouldLayerShow = false; + break; + } + } + } + _humanoidSystem.SetLayerVisibility(equipee, layer, shouldLayerShow); + } + protected virtual void OnGotEquipped(EntityUid uid, ClothingComponent component, GotEquippedEvent args) { component.InSlot = args.Slot; - if (args.Slot == "head" && _tagSystem.HasTag(args.Equipment, HairTag)) - _humanoidSystem.SetLayerVisibility(args.Equipee, HumanoidVisualLayers.Hair, false); + if ((new string[] { "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, HairTag)) + ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Hair, HairTag); + if ((new string[] { "mask", "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, NoseTag)) + ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Snout, NoseTag); } protected virtual void OnGotUnequipped(EntityUid uid, ClothingComponent component, GotUnequippedEvent args) { component.InSlot = null; - if (args.Slot == "head" && _tagSystem.HasTag(args.Equipment, HairTag)) - _humanoidSystem.SetLayerVisibility(args.Equipee, HumanoidVisualLayers.Hair, true); + if ((new string[] { "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, HairTag)) + ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Hair, HairTag); + if ((new string[] { "mask", "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, NoseTag)) + ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Snout, NoseTag); } private void OnGetState(EntityUid uid, ClothingComponent component, ref ComponentGetState args) @@ -113,8 +156,8 @@ public abstract class ClothingSystem : EntitySystem private void OnMaskToggled(Entity ent, ref ItemMaskToggledEvent args) { //TODO: sprites for 'pulled down' state. defaults to invisible due to no sprite with this prefix - if(args.equippedPrefix != null) - SetEquippedPrefix(ent, args.IsToggled ? args.equippedPrefix : null, ent); + SetEquippedPrefix(ent, args.IsToggled ? args.equippedPrefix : null, ent); + ToggleVisualLayer(args.Wearer, HumanoidVisualLayers.Snout, NoseTag); } private void OnEquipDoAfter(Entity ent, ref ClothingEquipDoAfterEvent args) diff --git a/Resources/Locale/en-US/markings/noses.ftl b/Resources/Locale/en-US/markings/noses.ftl new file mode 100644 index 0000000000..e49d87d559 --- /dev/null +++ b/Resources/Locale/en-US/markings/noses.ftl @@ -0,0 +1,14 @@ +marking-HumanNoseSchnozz = Schnozz +marking-HumanNoseSchnozz-schnozz = Nose + +marking-HumanNoseNubby = Nubby Nose +marking-HumanNoseNubby-nubby = Nose + +marking-HumanNoseDroop = Droopy Nose +marking-HumanNoseDroop-droop = Nose + +marking-HumanNoseBlob = Blobby Nose +marking-HumanNoseBlob-blob = Nose + +marking-HumanNoseUppie = Uppie Nose +marking-HumanNoseUppie-uppie = Nose diff --git a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml index 2d2d11524f..d13b284ff2 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml @@ -136,6 +136,7 @@ - HidesHair - WhitelistChameleon - HelmetEVA + - HidesNose - type: IdentityBlocker - type: entity @@ -174,6 +175,7 @@ tags: - HidesHair - WhitelistChameleon + - HidesNose - type: IdentityBlocker - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 358fc81c8b..25f641b1c4 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -17,6 +17,9 @@ sprite: Clothing/Head/Hardsuits/basic.rsi - type: Clothing sprite: Clothing/Head/Hardsuits/basic.rsi + - type: Tag + tags: + - HidesNose #Atmospherics Hardsuit - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml index c008a755ee..2d65e67982 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml @@ -22,6 +22,9 @@ - state: icon map: ["foldedLayer"] visible: false + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBandanaBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index 77655e7cdb..0b388aee6b 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -16,6 +16,7 @@ - MonkeyWearable - HamsterWearable - WhitelistChameleon + - HidesNose - type: entity parent: ClothingMaskGas @@ -195,6 +196,7 @@ tags: - ClownMask - WhitelistChameleon + - HidesNose - type: entity parent: ClothingMaskClownBase @@ -205,6 +207,7 @@ - ClownMask - HamsterWearable - WhitelistChameleon + - HidesNose - type: entity parent: ClothingMaskClown @@ -231,6 +234,9 @@ sprite: Clothing/Mask/joy.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase @@ -248,6 +254,7 @@ tags: - HamsterWearable - WhitelistChameleon + - HidesNose - type: entity parent: ClothingMaskPullableBase @@ -298,6 +305,9 @@ - type: BreathMask - type: IngestionBlocker - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskClownBase @@ -326,7 +336,9 @@ sprite: Clothing/Mask/swat.rsi - type: Tag tags: + - WhitelistChameleon - HidesHair + - HidesNose - type: entity parent: ClothingMaskGasExplorer @@ -351,7 +363,9 @@ sprite: Clothing/Mask/ert.rsi - type: Tag tags: + - WhitelistChameleon - HidesHair + - HidesNose - type: entity parent: ClothingMaskGasERT @@ -386,6 +400,7 @@ tags: - HamsterWearable - WhitelistChameleon + - HidesNose - type: IdentityBlocker - type: entity @@ -400,6 +415,9 @@ sprite: Clothing/Mask/fox.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase @@ -413,6 +431,9 @@ sprite: Clothing/Mask/bee.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase @@ -426,6 +447,9 @@ sprite: Clothing/Mask/bear.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase @@ -439,6 +463,9 @@ sprite: Clothing/Mask/raven.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase @@ -452,6 +479,9 @@ sprite: Clothing/Mask/jackal.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase @@ -465,6 +495,9 @@ sprite: Clothing/Mask/bat.rsi - type: BreathMask - type: IdentityBlocker + - type: Tag + tags: + - HidesNose - type: entity parent: ClothingMaskBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/specific.yml b/Resources/Prototypes/Entities/Clothing/Masks/specific.yml index e60c29d212..1e85073da9 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/specific.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: ClothingMaskBase id: ClothingMaskGasChameleon name: gas mask @@ -6,7 +6,8 @@ suffix: Chameleon components: - type: Tag - tags: [] # ignore "WhitelistChameleon" tag + tags: # ignore "WhitelistChameleon" tag + - HidesNose - type: Sprite sprite: Clothing/Mask/gas.rsi - type: Clothing diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_noses.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_noses.yml new file mode 100644 index 0000000000..51fc2fd15a --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_noses.yml @@ -0,0 +1,54 @@ +- type: marking + id: HumanNoseSchnozz + bodyPart: Snout + markingCategory: Snout + followSkinColor: true + forcedColoring: true + speciesRestriction: [Human, Dwarf] + sprites: + - sprite: Mobs/Customization/human_noses.rsi + state: schnozz + +- type: marking + id: HumanNoseNubby + bodyPart: Snout + markingCategory: Snout + followSkinColor: true + forcedColoring: true + speciesRestriction: [Human, Dwarf] + sprites: + - sprite: Mobs/Customization/human_noses.rsi + state: nubby + +- type: marking + id: HumanNoseDroop + bodyPart: Snout + markingCategory: Snout + followSkinColor: true + forcedColoring: true + speciesRestriction: [Human, Dwarf] + sprites: + - sprite: Mobs/Customization/human_noses.rsi + state: droop + +- type: marking + id: HumanNoseBlob + bodyPart: Snout + markingCategory: Snout + followSkinColor: true + forcedColoring: true + speciesRestriction: [Human, Dwarf] + sprites: + - sprite: Mobs/Customization/human_noses.rsi + state: blob + +- type: marking + id: HumanNoseUppie + bodyPart: Snout + markingCategory: Snout + followSkinColor: true + forcedColoring: true + speciesRestriction: [Human, Dwarf] + sprites: + - sprite: Mobs/Customization/human_noses.rsi + state: uppie diff --git a/Resources/Prototypes/Species/human.yml b/Resources/Prototypes/Species/human.yml index 979e226c81..0cbd9cc03f 100644 --- a/Resources/Prototypes/Species/human.yml +++ b/Resources/Prototypes/Species/human.yml @@ -20,6 +20,7 @@ Head: MobHumanHead Hair: MobHumanoidAnyMarking FacialHair: MobHumanoidAnyMarking + Snout: MobHumanoidAnyMarking Chest: MobHumanTorso Eyes: MobHumanoidEyes LArm: MobHumanLArm @@ -40,6 +41,9 @@ FacialHair: points: 1 required: false + Snout: + points: 1 + required: false Tail: # the cat tail joke points: 0 required: false diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 6e13da6a9a..e2d08042b5 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -653,6 +653,9 @@ - type: Tag id: HidesHair # for headwear. +- type: Tag + id: HidesNose # for non-standard noses. + - type: Tag id: HighRiskItem diff --git a/Resources/Textures/Mobs/Customization/human_noses.rsi/blob.png b/Resources/Textures/Mobs/Customization/human_noses.rsi/blob.png new file mode 100644 index 0000000000..31774b81f9 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_noses.rsi/blob.png differ diff --git a/Resources/Textures/Mobs/Customization/human_noses.rsi/droop.png b/Resources/Textures/Mobs/Customization/human_noses.rsi/droop.png new file mode 100644 index 0000000000..57bed8e5bd Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_noses.rsi/droop.png differ diff --git a/Resources/Textures/Mobs/Customization/human_noses.rsi/meta.json b/Resources/Textures/Mobs/Customization/human_noses.rsi/meta.json new file mode 100644 index 0000000000..af67414763 --- /dev/null +++ b/Resources/Textures/Mobs/Customization/human_noses.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version":1, + "size": { + "x":32, + "y":32 + }, + "copyright":"Created by SlamBamActionman", + "license":"CC-BY-SA-3.0", + "states": [ + { + "name":"schnozz", + "directions":4 + }, + { + "name":"blob", + "directions":4 + }, + { + "name":"droop", + "directions":4 + }, + { + "name":"uppie", + "directions":4 + }, + { + "name":"nubby", + "directions":4 + } + ] +} diff --git a/Resources/Textures/Mobs/Customization/human_noses.rsi/nubby.png b/Resources/Textures/Mobs/Customization/human_noses.rsi/nubby.png new file mode 100644 index 0000000000..ab5bdde977 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_noses.rsi/nubby.png differ diff --git a/Resources/Textures/Mobs/Customization/human_noses.rsi/schnozz.png b/Resources/Textures/Mobs/Customization/human_noses.rsi/schnozz.png new file mode 100644 index 0000000000..618c5f5eb7 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_noses.rsi/schnozz.png differ diff --git a/Resources/Textures/Mobs/Customization/human_noses.rsi/uppie.png b/Resources/Textures/Mobs/Customization/human_noses.rsi/uppie.png new file mode 100644 index 0000000000..a1be557443 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_noses.rsi/uppie.png differ