From 390f8d19d1505364389e1f595a54df2cfa43a96e Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Sun, 16 Jun 2024 22:21:29 -0500 Subject: [PATCH] Makes Eyepatches Flippable (#26277) --- .../Clothing/ClientClothingSystem.cs | 8 ++-- .../FlippableClothingVisualizerSystem.cs | 48 +++++++++++++++++++ .../FlippableClothingVisualsComponent.cs | 16 +++++++ Content.Client/Sprite/RandomSpriteSystem.cs | 3 -- .../Clothing/Components/ClothingComponent.cs | 8 +++- .../Clothing/EntitySystems/ClothingSystem.cs | 6 --- .../EntitySystems/FoldableClothingSystem.cs | 40 ++++++++-------- .../Clothing/Eyes/base_clothingeyes.yml | 39 +++++++++++++++ .../Prototypes/Entities/Clothing/Eyes/hud.yml | 32 +++++++++---- .../Entities/Clothing/Eyes/misc.yml | 31 +++++++----- 10 files changed, 175 insertions(+), 56 deletions(-) create mode 100644 Content.Client/Clothing/FlippableClothingVisualizerSystem.cs create mode 100644 Content.Client/Clothing/FlippableClothingVisualsComponent.cs diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs index dd69521f48..1c0d831226 100644 --- a/Content.Client/Clothing/ClientClothingSystem.cs +++ b/Content.Client/Clothing/ClientClothingSystem.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Numerics; using Content.Client.Inventory; using Content.Shared.Clothing; using Content.Shared.Clothing.Components; @@ -113,6 +114,7 @@ public sealed class ClientClothingSystem : ClothingSystem i++; } + item.MappedLayer = key; args.Layers.Add((key, layer)); } } @@ -153,13 +155,9 @@ public sealed class ClientClothingSystem : ClothingSystem // species specific if (speciesId != null && rsi.TryGetState($"{state}-{speciesId}", out _)) - { state = $"{state}-{speciesId}"; - } else if (!rsi.TryGetState(state, out _)) - { return false; - } var layer = new PrototypeLayerData(); layer.RsiPath = rsi.Path.ToString(); @@ -287,6 +285,8 @@ public sealed class ClientClothingSystem : ClothingSystem if (layerData.Color != null) sprite.LayerSetColor(key, layerData.Color.Value); + if (layerData.Scale != null) + sprite.LayerSetScale(key, layerData.Scale.Value); } else index = sprite.LayerMapReserveBlank(key); diff --git a/Content.Client/Clothing/FlippableClothingVisualizerSystem.cs b/Content.Client/Clothing/FlippableClothingVisualizerSystem.cs new file mode 100644 index 0000000000..2c3afb0324 --- /dev/null +++ b/Content.Client/Clothing/FlippableClothingVisualizerSystem.cs @@ -0,0 +1,48 @@ +using Content.Shared.Clothing; +using Content.Shared.Clothing.Components; +using Content.Shared.Clothing.EntitySystems; +using Content.Shared.Foldable; +using Content.Shared.Item; +using Robust.Client.GameObjects; + +namespace Content.Client.Clothing; + +public sealed class FlippableClothingVisualizerSystem : VisualizerSystem +{ + [Dependency] private readonly SharedItemSystem _itemSys = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetVisuals, after: [typeof(ClothingSystem)]); + SubscribeLocalEvent(OnFolded); + } + + private void OnFolded(Entity ent, ref FoldedEvent args) + { + _itemSys.VisualsChanged(ent); + } + + private void OnGetVisuals(Entity ent, ref GetEquipmentVisualsEvent args) + { + if (!TryComp(ent, out SpriteComponent? sprite) || + !TryComp(ent, out ClothingComponent? clothing)) + return; + + if (clothing.MappedLayer == null || + !AppearanceSystem.TryGetData(ent, FoldableSystem.FoldedVisuals.State, out var folding) || + !sprite.LayerMapTryGet(folding ? ent.Comp.FoldingLayer : ent.Comp.UnfoldingLayer, out var idx)) + return; + + // add each layer to the visuals + var spriteLayer = sprite[idx]; + foreach (var layer in args.Layers) + { + if (layer.Item1 != clothing.MappedLayer) + continue; + + layer.Item2.Scale = spriteLayer.Scale; + } + } +} diff --git a/Content.Client/Clothing/FlippableClothingVisualsComponent.cs b/Content.Client/Clothing/FlippableClothingVisualsComponent.cs new file mode 100644 index 0000000000..33d622b8b5 --- /dev/null +++ b/Content.Client/Clothing/FlippableClothingVisualsComponent.cs @@ -0,0 +1,16 @@ +namespace Content.Client.Clothing; + +/// +/// Communicates folded layers data (currently only Scale to handle flipping) +/// to the wearer clothing sprite layer +/// +[RegisterComponent] +[Access(typeof(FlippableClothingVisualizerSystem))] +public sealed partial class FlippableClothingVisualsComponent : Component +{ + [DataField] + public string FoldingLayer = "foldedLayer"; + + [DataField] + public string UnfoldingLayer = "unfoldedLayer"; +} diff --git a/Content.Client/Sprite/RandomSpriteSystem.cs b/Content.Client/Sprite/RandomSpriteSystem.cs index b9be2a44b4..c4aa43a65b 100644 --- a/Content.Client/Sprite/RandomSpriteSystem.cs +++ b/Content.Client/Sprite/RandomSpriteSystem.cs @@ -43,9 +43,6 @@ public sealed class RandomSpriteSystem : SharedRandomSpriteSystem if (!Resolve(uid, ref clothing, false)) return; - if (clothing.ClothingVisuals == null) - return; - foreach (var slotPair in clothing.ClothingVisuals) { foreach (var keyColorPair in component.Selected) diff --git a/Content.Shared/Clothing/Components/ClothingComponent.cs b/Content.Shared/Clothing/Components/ClothingComponent.cs index 6d7226e767..846a78b868 100644 --- a/Content.Shared/Clothing/Components/ClothingComponent.cs +++ b/Content.Shared/Clothing/Components/ClothingComponent.cs @@ -16,9 +16,14 @@ namespace Content.Shared.Clothing.Components; public sealed partial class ClothingComponent : Component { [DataField("clothingVisuals")] - [Access(typeof(ClothingSystem), typeof(InventorySystem), Other = AccessPermissions.ReadExecute)] // TODO remove execute permissions. public Dictionary> ClothingVisuals = new(); + /// + /// The name of the layer in the user that this piece of clothing will map to + /// + [DataField] + public string? MappedLayer; + [ViewVariables(VVAccess.ReadWrite)] [DataField("quickEquip")] public bool QuickEquip = true; @@ -121,4 +126,3 @@ public sealed partial class ClothingUnequipDoAfterEvent : DoAfterEvent public override DoAfterEvent Clone() => this; } - diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index 1e2825a49a..bdcb2c8204 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -241,9 +241,6 @@ public abstract class ClothingSystem : EntitySystem public void SetLayerColor(ClothingComponent clothing, string slot, string mapKey, Color? color) { - if (clothing.ClothingVisuals == null) - return; - foreach (var layer in clothing.ClothingVisuals[slot]) { if (layer.MapKeys == null) @@ -257,9 +254,6 @@ public abstract class ClothingSystem : EntitySystem } public void SetLayerState(ClothingComponent clothing, string slot, string mapKey, string state) { - if (clothing.ClothingVisuals == null) - return; - foreach (var layer in clothing.ClothingVisuals[slot]) { if (layer.MapKeys == null) diff --git a/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs index 27ea168018..be55588ddd 100644 --- a/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs @@ -33,32 +33,32 @@ public sealed class FoldableClothingSystem : EntitySystem private void OnFolded(Entity ent, ref FoldedEvent args) { - if (TryComp(ent.Owner, out var clothingComp) && - TryComp(ent.Owner, out var itemComp)) + if (!TryComp(ent.Owner, out var clothingComp) || + !TryComp(ent.Owner, out var itemComp)) + return; + + if (args.IsFolded) { - if (args.IsFolded) - { - if (ent.Comp.FoldedSlots.HasValue) - _clothingSystem.SetSlots(ent.Owner, ent.Comp.FoldedSlots.Value, clothingComp); + if (ent.Comp.FoldedSlots.HasValue) + _clothingSystem.SetSlots(ent.Owner, ent.Comp.FoldedSlots.Value, clothingComp); - if (ent.Comp.FoldedEquippedPrefix != null) - _clothingSystem.SetEquippedPrefix(ent.Owner, ent.Comp.FoldedEquippedPrefix, clothingComp); + if (ent.Comp.FoldedEquippedPrefix != null) + _clothingSystem.SetEquippedPrefix(ent.Owner, ent.Comp.FoldedEquippedPrefix, clothingComp); - if (ent.Comp.FoldedHeldPrefix != null) - _itemSystem.SetHeldPrefix(ent.Owner, ent.Comp.FoldedHeldPrefix, false, itemComp); - } - else - { - if (ent.Comp.UnfoldedSlots.HasValue) - _clothingSystem.SetSlots(ent.Owner, ent.Comp.UnfoldedSlots.Value, clothingComp); + if (ent.Comp.FoldedHeldPrefix != null) + _itemSystem.SetHeldPrefix(ent.Owner, ent.Comp.FoldedHeldPrefix, false, itemComp); + } + else + { + if (ent.Comp.UnfoldedSlots.HasValue) + _clothingSystem.SetSlots(ent.Owner, ent.Comp.UnfoldedSlots.Value, clothingComp); - if (ent.Comp.FoldedEquippedPrefix != null) - _clothingSystem.SetEquippedPrefix(ent.Owner, null, clothingComp); + if (ent.Comp.FoldedEquippedPrefix != null) + _clothingSystem.SetEquippedPrefix(ent.Owner, null, clothingComp); - if (ent.Comp.FoldedHeldPrefix != null) - _itemSystem.SetHeldPrefix(ent.Owner, null, false, itemComp); + if (ent.Comp.FoldedHeldPrefix != null) + _itemSystem.SetHeldPrefix(ent.Owner, null, false, itemComp); - } } } } diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml b/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml index 10f265a4a2..b31f821629 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml @@ -10,3 +10,42 @@ - type: Item size: Small storedRotation: -90 + +- type: entity + parent: [ClothingEyesBase, BaseFoldable] + id: ClothingHeadEyeBaseFlippable + abstract: true + components: + - type: Appearance + - type: FlippableClothingVisuals + - type: Foldable + canFoldInsideContainer: true + unfoldVerbText: fold-flip-verb + foldVerbText: fold-flip-verb + - type: FoldableClothing + - type: Sprite + layers: + - map: [ "unfoldedLayer" ] + state: icon + - map: ["foldedLayer"] + state: icon + visible: false + scale: -1,1 + +- type: entity + parent: ClothingHeadEyeBaseFlippable + id: ClothingHeadEyeBaseFlipped + suffix: flipped + abstract: true + components: + - type: Foldable + folded: true + - type: Sprite + layers: + - map: [ "unfoldedLayer" ] + state: icon + visible: false + - map: ["foldedLayer"] + state: icon + visible: true + scale: -1,1 diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml index c74a60e8fc..0c7fc5b2a1 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml @@ -220,7 +220,7 @@ suffix: Syndicate - type: entity - parent: ClothingEyesHudMedical + parent: [ClothingEyesHudMedical, ClothingHeadEyeBaseFlippable] id: ClothingEyesEyepatchHudMedical name: medical hud eyepatch description: A heads-up display that scans the humanoids in view and provides accurate data about their health status. For true patriots. @@ -231,7 +231,12 @@ sprite: Clothing/Eyes/Hud/medpatch.rsi - type: entity - parent: ClothingEyesHudSecurity + parent: [ClothingEyesEyepatchHudMedical, ClothingHeadEyeBaseFlipped] + id: ClothingEyesEyepatchHudMedicalFlipped + name: medical hud eyepatch + +- type: entity + parent: [ClothingEyesHudSecurity, ClothingHeadEyeBaseFlippable] id: ClothingEyesEyepatchHudSecurity name: security hud eyepatch description: A heads-up display that scans the humanoids in view and provides accurate data about their ID status and security records. For true patriots. @@ -242,7 +247,12 @@ sprite: Clothing/Eyes/Hud/secpatch.rsi - type: entity - parent: ClothingEyesHudBeer + parent: [ClothingEyesEyepatchHudSecurity, ClothingHeadEyeBaseFlipped] + id: ClothingEyesEyepatchHudSecurityFlipped + name: security hud eyepatch + +- type: entity + parent: [ClothingEyesHudBeer, ClothingHeadEyeBaseFlippable] id: ClothingEyesEyepatchHudBeer name: beer hud eyepatch description: A pair of sunHud outfitted with apparatus to scan reagents, as well as providing an innate understanding of liquid viscosity while in motion. For true patriots. @@ -253,7 +263,12 @@ sprite: Clothing/Eyes/Hud/beerpatch.rsi - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesEyepatchHudBeer, ClothingHeadEyeBaseFlipped] + id: ClothingEyesEyepatchHudBeerFlipped + name: beer hud eyepatch + +- type: entity + parent: [ClothingEyesHudDiagnostic, ClothingHeadEyeBaseFlippable] id: ClothingEyesEyepatchHudDiag name: diagnostic hud eyepatch description: A heads-up display capable of analyzing the integrity and status of robotics and exosuits. Made out of see-borg-ium. @@ -262,7 +277,8 @@ sprite: Clothing/Eyes/Hud/diagpatch.rsi - type: Clothing sprite: Clothing/Eyes/Hud/diagpatch.rsi - - type: ShowHealthBars - damageContainers: - - Inorganic - - Silicon + +- type: entity + parent: [ClothingEyesEyepatchHudDiag, ClothingHeadEyeBaseFlipped] + id: ClothingEyesEyepatchHudDiagFlipped + name: diagnostic hud eyepatch diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/misc.yml b/Resources/Prototypes/Entities/Clothing/Eyes/misc.yml index 06ff347172..075ccae1c4 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/misc.yml @@ -1,16 +1,3 @@ -- type: entity - parent: ClothingEyesBase - id: ClothingEyesEyepatch - name: eyepatch - description: Yarr. - components: - - type: Sprite - sprite: Clothing/Eyes/Misc/eyepatch.rsi - - type: Clothing - sprite: Clothing/Eyes/Misc/eyepatch.rsi - - type: EyeProtection - protectionTime: 5 - - type: entity parent: ClothingEyesBase id: ClothingEyesBlindfold @@ -26,3 +13,21 @@ graph: Blindfold node: blindfold - type: FlashImmunity + +- type: entity + parent: ClothingHeadEyeBaseFlippable + id: ClothingEyesEyepatch + name: eyepatch + description: Yarr. + components: + - type: Sprite + sprite: Clothing/Eyes/Misc/eyepatch.rsi + - type: Clothing + sprite: Clothing/Eyes/Misc/eyepatch.rsi + - type: EyeProtection + protectionTime: 5 + +- type: entity + parent: [ClothingEyesEyepatch, ClothingHeadEyeBaseFlipped] + id: ClothingEyesEyepatchFlipped + suffix: flipped