diff --git a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs index 0d58eb9663..9040ac7d1f 100644 --- a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs +++ b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Ghost; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Prototypes; @@ -86,28 +87,31 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem HumanoidAppearanceComponent component, SpriteComponent sprite, HumanoidVisualLayers key, - string protoId, + string? protoId, bool sexMorph = false, Color? color = null) { + var layerIndex = sprite.LayerMapReserveBlank(key); + var layer = sprite[layerIndex]; + layer.Visible = !IsHidden(component, key); + + if (color != null) + layer.Color = color.Value; + + if (protoId == null) + return; + if (sexMorph) protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId); var proto = _prototypeManager.Index(protoId); component.BaseLayers[key] = proto; - var layerIndex = sprite.LayerMapReserveBlank(key); - var layer = sprite[layerIndex]; - - if (color != null) - layer.Color = color.Value; - else if (proto.MatchSkin) - layer.Color = proto.MatchSkin ? component.SkinColor.WithAlpha(proto.LayerAlpha) : Color.White; + if (proto.MatchSkin) + layer.Color = component.SkinColor.WithAlpha(proto.LayerAlpha); if (proto.BaseSprite != null) sprite.LayerSetSprite(layerIndex, proto.BaseSprite); - - layer.Visible = !IsHidden(component, key); } /// diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs index bc6c3338e2..178e9a173e 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs @@ -1,9 +1,11 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; +using Content.Shared.Humanoid.Prototypes; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Client.Humanoid; @@ -18,12 +20,14 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow public Action? OnMarkingColorChange; public Action? OnMarkingRankChange; public Action? OnLayerInfoModified; + private readonly IPrototypeManager _protoMan = default!; private readonly Dictionary _modifiers = new(); public HumanoidMarkingModifierWindow() { RobustXamlLoader.Load(this); + _protoMan = IoCManager.Resolve(); foreach (var layer in Enum.GetValues()) { @@ -31,14 +35,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow BaseLayersContainer.AddChild(modifier); _modifiers.Add(layer, modifier); - modifier.OnStateChanged += delegate - { - OnLayerInfoModified!( - layer, - modifier.Enabled - ? new CustomBaseLayerInfo(modifier.State, modifier.Color) - : null); - }; + modifier.OnStateChanged += () => OnStateChanged(layer, modifier); } MarkingPickerWidget.OnMarkingAdded += set => OnMarkingAdded!(set); @@ -52,6 +49,18 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow MarkingPickerWidget.IgnoreSpecies = MarkingForced.Pressed; } + private void OnStateChanged(HumanoidVisualLayers layer, HumanoidBaseLayerModifier modifier) + { + if (!modifier.Enabled) + { + OnLayerInfoModified?.Invoke(layer, null); + return; + } + + string? state = _protoMan.HasIndex(modifier.Text) ? modifier.Text : null; + OnLayerInfoModified?.Invoke(layer, new CustomBaseLayerInfo(state, modifier.Color)); + } + public void SetState(MarkingSet markings, string species, Color skinColor, Dictionary info) { MarkingPickerWidget.SetData(markings, species, skinColor); @@ -64,7 +73,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow continue; } - modifier.SetState(true, layerInfo.ID, layerInfo.Color ?? Color.White); + modifier.SetState(true, layerInfo.ID ?? string.Empty, layerInfo.Color ?? Color.White); } } @@ -76,7 +85,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow private BoxContainer _infoBox; public bool Enabled => _enable.Pressed; - public string State => _lineEdit.Text; + public string Text => _lineEdit.Text; public Color Color => _colorSliders.Color; public Action? OnStateChanged; @@ -117,7 +126,9 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow var lineEditBox = new BoxContainer(); lineEditBox.AddChild(new Label { Text = "Prototype id: "}); - _lineEdit = new(); + + // TODO: This line edit should really be an options / dropdown selector, not text. + _lineEdit = new() { MinWidth = 200 }; _lineEdit.OnTextEntered += args => OnStateChanged!(); lineEditBox.AddChild(_lineEdit); _infoBox.AddChild(lineEditBox); diff --git a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs index 180475bcef..35c713d5e1 100644 --- a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs +++ b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs @@ -114,9 +114,9 @@ public sealed class HumanoidAppearanceState : ComponentState [Serializable, NetSerializable] public readonly struct CustomBaseLayerInfo { - public CustomBaseLayerInfo(string id, Color? color = null) + public CustomBaseLayerInfo(string? id, Color? color = null) { - DebugTools.Assert(IoCManager.Resolve().HasIndex(id)); + DebugTools.Assert(id == null || IoCManager.Resolve().HasIndex(id)); ID = id; Color = color; } @@ -124,11 +124,11 @@ public sealed class HumanoidAppearanceState : ComponentState /// /// ID of this custom base layer. Must be a . /// - [DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] - public string ID { init; get; } + [DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? ID { init; get; } /// - /// Color of this custom base layer. Null implies skin colour. + /// Color of this custom base layer. Null implies skin colour if the corresponding is set to match skin. /// [DataField("color")] public Color? Color { init; get; } diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index 1004a5bf54..e803313a10 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -165,7 +165,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem /// The ID of the sprite to use. See . /// Whether to synchronize this to the humanoid mob, or not. /// Humanoid component of the entity - public void SetBaseLayerId(EntityUid uid, HumanoidVisualLayers layer, string id, bool sync = true, + public void SetBaseLayerId(EntityUid uid, HumanoidVisualLayers layer, string? id, bool sync = true, HumanoidAppearanceComponent? humanoid = null) { if (!Resolve(uid, ref humanoid)) @@ -192,7 +192,10 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem if (!Resolve(uid, ref humanoid)) return; - humanoid.CustomBaseLayers[layer] = humanoid.CustomBaseLayers[layer] with { Color = color }; + if (humanoid.CustomBaseLayers.TryGetValue(layer, out var info)) + humanoid.CustomBaseLayers[layer] = info with { Color = color }; + else + humanoid.CustomBaseLayers[layer] = new(null, color); if (sync) Dirty(humanoid);