using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Numerics;
using Content.Client.Inventory;
using Content.Shared.Clothing;
using Content.Shared.Clothing.Components;
i++;
}
+ item.MappedLayer = key;
args.Layers.Add((key, layer));
}
}
// 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();
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);
--- /dev/null
+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<FlippableClothingVisualsComponent>
+{
+ [Dependency] private readonly SharedItemSystem _itemSys = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<FlippableClothingVisualsComponent, GetEquipmentVisualsEvent>(OnGetVisuals, after: [typeof(ClothingSystem)]);
+ SubscribeLocalEvent<FlippableClothingVisualsComponent, FoldedEvent>(OnFolded);
+ }
+
+ private void OnFolded(Entity<FlippableClothingVisualsComponent> ent, ref FoldedEvent args)
+ {
+ _itemSys.VisualsChanged(ent);
+ }
+
+ private void OnGetVisuals(Entity<FlippableClothingVisualsComponent> ent, ref GetEquipmentVisualsEvent args)
+ {
+ if (!TryComp(ent, out SpriteComponent? sprite) ||
+ !TryComp(ent, out ClothingComponent? clothing))
+ return;
+
+ if (clothing.MappedLayer == null ||
+ !AppearanceSystem.TryGetData<bool>(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;
+ }
+ }
+}
--- /dev/null
+namespace Content.Client.Clothing;
+
+/// <summary>
+/// Communicates folded layers data (currently only Scale to handle flipping)
+/// to the wearer clothing sprite layer
+/// </summary>
+[RegisterComponent]
+[Access(typeof(FlippableClothingVisualizerSystem))]
+public sealed partial class FlippableClothingVisualsComponent : Component
+{
+ [DataField]
+ public string FoldingLayer = "foldedLayer";
+
+ [DataField]
+ public string UnfoldingLayer = "unfoldedLayer";
+}
if (!Resolve(uid, ref clothing, false))
return;
- if (clothing.ClothingVisuals == null)
- return;
-
foreach (var slotPair in clothing.ClothingVisuals)
{
foreach (var keyColorPair in component.Selected)
public sealed partial class ClothingComponent : Component
{
[DataField("clothingVisuals")]
- [Access(typeof(ClothingSystem), typeof(InventorySystem), Other = AccessPermissions.ReadExecute)] // TODO remove execute permissions.
public Dictionary<string, List<PrototypeLayerData>> ClothingVisuals = new();
+ /// <summary>
+ /// The name of the layer in the user that this piece of clothing will map to
+ /// </summary>
+ [DataField]
+ public string? MappedLayer;
+
[ViewVariables(VVAccess.ReadWrite)]
[DataField("quickEquip")]
public bool QuickEquip = true;
public override DoAfterEvent Clone() => this;
}
-
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)
}
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)
private void OnFolded(Entity<FoldableClothingComponent> ent, ref FoldedEvent args)
{
- if (TryComp<ClothingComponent>(ent.Owner, out var clothingComp) &&
- TryComp<ItemComponent>(ent.Owner, out var itemComp))
+ if (!TryComp<ClothingComponent>(ent.Owner, out var clothingComp) ||
+ !TryComp<ItemComponent>(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);
- }
}
}
}
- 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
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.
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.
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.
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.
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
-- 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
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