From 8b3d7728d7bffef1990df8ccf0d23f54d5e497bc Mon Sep 17 00:00:00 2001 From: csqrb <56765288+CaptainSqrBeard@users.noreply.github.com> Date: Sun, 5 Mar 2023 08:59:07 +0600 Subject: [PATCH] Marking default coloring (#13039) * Marking coloring WIP * EnsureDefault now supports coloring! * Now markings have coloring when they get added * Many things * yml files * cleanup * Some requested changes * Nullable type and WIP caching * Time to resolve that thing with deprecated hair fields * Latest reviews + im still trying to use these hair markings * FirstOrDefault thing and Tattoo docs * IDK * It's now works a bit more properly in preferences GUI * THEY SYNCING! However preferences GUI still broken and doesn't work properly * Markings now updating when changing in GUI. However they still don't work properly with bald humanoids * Forgor... * Default hair-colored markings will not color to hair if there is no hair * Fixed default colors for customizable markings * Fixed bug in prefs GUI that set current hair to null * Now markings that must match skin color because of limb (e.x. Slimes) - will match skin color * final tweaks: if hair uses skin color then markings will use skin color as hair color (slimes) * fix * fixed dirty. no more funni invis bug * Mirrors and client profile loading * default colors soon TM * review + better coloring * Hardcode is gone * diona markings * oh my god * fixed CategoryColoring * cool fallback, clean up and some other tweaks * code style * more style * a --- .../Humanoid/HumanoidAppearanceSystem.cs | 80 +++++++--- .../HumanoidMarkingModifierWindow.xaml.cs | 18 ++- Content.Client/Humanoid/MarkingPicker.xaml.cs | 56 +++++-- .../UI/HumanoidProfileEditor.xaml.cs | 95 ++++++++++- .../Systems/HumanoidAppearanceSystem.cs | 56 ++++++- .../Systems/HumanoidSystem.Modifier.cs | 15 +- .../MagicMirror/MagicMirrorSystem.cs | 2 +- .../Humanoid/HumanoidAppearanceComponent.cs | 12 ++ .../Humanoid/HumanoidCharacterAppearance.cs | 2 +- .../Humanoid/HumanoidVisualLayers.cs | 3 +- .../ColoringTypes/CategoryColoring.cs | 24 +++ .../Markings/ColoringTypes/EyeColoring.cs | 12 ++ .../Markings/ColoringTypes/SimpleColoring.cs | 15 ++ .../Markings/ColoringTypes/SkinColoring.cs | 12 ++ .../Markings/ColoringTypes/TattooColoring.cs | 20 +++ Content.Shared/Humanoid/Markings/Marking.cs | 10 ++ .../Humanoid/Markings/MarkingColoring.cs | 147 ++++++++++++++++++ .../Humanoid/Markings/MarkingManager.cs | 64 ++++++++ .../Humanoid/Markings/MarkingPrototype.cs | 8 +- .../Humanoid/Markings/MarkingsSet.cs | 67 +++++--- .../SharedHumanoidAppearanceSystem.cs | 2 +- .../SharedHumanoidMarkingModifierSystem.cs | 10 +- .../Mobs/Customization/Markings/cat_parts.yml | 21 +++ .../Mobs/Customization/Markings/diona.yml | 138 ++++++++++++++++ .../Mobs/Customization/Markings/reptilian.yml | 7 +- .../Mobs/Customization/Markings/tattoos.yml | 50 ++++++ 26 files changed, 863 insertions(+), 83 deletions(-) create mode 100644 Content.Shared/Humanoid/Markings/ColoringTypes/CategoryColoring.cs create mode 100644 Content.Shared/Humanoid/Markings/ColoringTypes/EyeColoring.cs create mode 100644 Content.Shared/Humanoid/Markings/ColoringTypes/SimpleColoring.cs create mode 100644 Content.Shared/Humanoid/Markings/ColoringTypes/SkinColoring.cs create mode 100644 Content.Shared/Humanoid/Markings/ColoringTypes/TattooColoring.cs create mode 100644 Content.Shared/Humanoid/Markings/MarkingColoring.cs diff --git a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs index 9040ac7d1f..47ef6a0607 100644 --- a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs +++ b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.Ghost; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; @@ -42,6 +43,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem component.PermanentlyHidden = new(state.PermanentlyHidden); component.CustomBaseLayers = state.CustomBaseLayers.ShallowClone(); + UpdateLayers(component, sprite); ApplyMarkingSet(uid, state.Markings, component, sprite); @@ -134,22 +136,66 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem var customBaseLayers = new Dictionary(); var speciesPrototype = _prototypeManager.Index(profile.Species); - var markings = new MarkingSet(profile.Appearance.Markings, speciesPrototype.MarkingPoints, _markingManager, - _prototypeManager); - markings.EnsureDefault(profile.Appearance.SkinColor, _markingManager); + var markings = new MarkingSet(speciesPrototype.MarkingPoints, _markingManager, _prototypeManager); + + // Add markings that doesn't need coloring. We store them until we add all other markings that doesn't need it. + var markingFColored = new Dictionary(); + foreach (var marking in profile.Appearance.Markings) + { + if (_markingManager.TryGetMarking(marking, out var prototype)) + { + if (!prototype.ForcedColoring) + { + markings.AddBack(prototype.MarkingCategory, marking); + } + else + { + markingFColored.Add(marking, prototype); + } + } + } // legacy: remove in the future? - markings.RemoveCategory(MarkingCategories.Hair); - markings.RemoveCategory(MarkingCategories.FacialHair); - - var hair = new Marking(profile.Appearance.HairStyleId, new[] { profile.Appearance.HairColor }); - markings.AddBack(MarkingCategories.Hair, hair); + //markings.RemoveCategory(MarkingCategories.Hair); + //markings.RemoveCategory(MarkingCategories.FacialHair); + // We need to ensure hair before applying it or coloring can try depend on markings that can be invalid + var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, _prototypeManager) + ? profile.Appearance.SkinColor : profile.Appearance.HairColor; + var hair = new Marking(profile.Appearance.HairStyleId, + new[] { hairColor }); + + var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, _prototypeManager) + ? profile.Appearance.SkinColor : profile.Appearance.FacialHairColor; var facialHair = new Marking(profile.Appearance.FacialHairStyleId, - new[] { profile.Appearance.FacialHairColor }); - markings.AddBack(MarkingCategories.FacialHair, facialHair); + new[] { facialHairColor }); - markings.FilterSpecies(profile.Species, _markingManager, _prototypeManager); + if (_markingManager.CanBeApplied(profile.Species, hair, _prototypeManager)) + { + markings.AddBack(MarkingCategories.Hair, hair); + } + if (_markingManager.CanBeApplied(profile.Species, facialHair, _prototypeManager)) + { + markings.AddBack(MarkingCategories.FacialHair, facialHair); + } + + // Finally adding marking with forced colors + foreach (var (marking, prototype) in markingFColored) + { + var markingColors = MarkingColoring.GetMarkingLayerColors( + prototype, + profile.Appearance.SkinColor, + profile.Appearance.EyeColor, + markings + ); + markings.AddBack(prototype.MarkingCategory, new Marking(marking.MarkingId, markingColors)); + } + + markings.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager); + markings.EnsureDefault( + profile.Appearance.SkinColor, + profile.Appearance.EyeColor, + _markingManager); DebugTools.Assert(uid.IsClientSide()); @@ -239,7 +285,6 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem spriteComp.RemoveLayer(index); } } - private void ApplyMarking(EntityUid uid, MarkingPrototype markingPrototype, IReadOnlyList? colors, @@ -273,22 +318,19 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem } sprite.LayerSetVisible(layerId, visible); - + if (!visible || setting == null) // this is kinda implied { continue; } - if (markingPrototype.FollowSkinColor || colors == null || setting.MarkingsMatchSkin) + if (colors != null) { - var skinColor = humanoid.SkinColor; - skinColor.A = setting.LayerAlpha; - - sprite.LayerSetColor(layerId, skinColor); + sprite.LayerSetColor(layerId, colors[j]); } else { - sprite.LayerSetColor(layerId, colors[j]); + sprite.LayerSetColor(layerId, Color.White); } } } diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs index 178e9a173e..ea39c501b3 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs @@ -60,11 +60,13 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow 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) + public void SetState( + MarkingSet markings, + string species, + Color skinColor, + Dictionary info + ) { - MarkingPickerWidget.SetData(markings, species, skinColor); - foreach (var (layer, modifier) in _modifiers) { if (!info.TryGetValue(layer, out var layerInfo)) @@ -75,6 +77,14 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow modifier.SetState(true, layerInfo.ID ?? string.Empty, layerInfo.Color ?? Color.White); } + + var eyesColor = Color.White; + if (info.TryGetValue(HumanoidVisualLayers.Eyes, out var eyes) && eyes.Color != null) + { + eyesColor = eyes.Color.Value; + } + + MarkingPickerWidget.SetData(markings, species, skinColor, eyesColor); } private sealed class HumanoidBaseLayerModifier : BoxContainer diff --git a/Content.Client/Humanoid/MarkingPicker.xaml.cs b/Content.Client/Humanoid/MarkingPicker.xaml.cs index 6d9e94f7f6..f284b84cd2 100644 --- a/Content.Client/Humanoid/MarkingPicker.xaml.cs +++ b/Content.Client/Humanoid/MarkingPicker.xaml.cs @@ -36,6 +36,9 @@ public sealed partial class MarkingPicker : Control private string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies; public Color CurrentSkinColor = Color.White; + public Color CurrentEyeColor = Color.Black; + public Marking? HairMarking; + public Marking? FacialHairMarking; private readonly HashSet _ignoreCategories = new(); @@ -74,7 +77,7 @@ public sealed partial class MarkingPicker : Control } } - public void SetData(List newMarkings, string species, Color skinColor) + public void SetData(List newMarkings, string species, Color skinColor, Color eyeColor) { var pointsProto = _prototypeManager .Index(species).MarkingPoints; @@ -82,33 +85,36 @@ public sealed partial class MarkingPicker : Control if (!IgnoreSpecies) { - _currentMarkings.FilterSpecies(species); // should be validated server-side but it can't hurt + _currentMarkings.EnsureSpecies(species, skinColor, _markingManager); // should be validated server-side but it can't hurt } _currentSpecies = species; CurrentSkinColor = skinColor; + CurrentEyeColor = eyeColor; Populate(); PopulateUsed(); } - public void SetData(MarkingSet set, string species, Color skinColor) + public void SetData(MarkingSet set, string species, Color skinColor, Color eyeColor) { _currentMarkings = set; if (!IgnoreSpecies) { - _currentMarkings.FilterSpecies(species); // should be validated server-side but it can't hurt + _currentMarkings.EnsureSpecies(species, skinColor, _markingManager); // should be validated server-side but it can't hurt } _currentSpecies = species; CurrentSkinColor = skinColor; + CurrentEyeColor = eyeColor; Populate(); PopulateUsed(); } public void SetSkinColor(Color color) => CurrentSkinColor = color; + public void SetEyeColor(Color color) => CurrentEyeColor = color; public MarkingPicker() { @@ -201,7 +207,7 @@ public sealed partial class MarkingPicker : Control if (!IgnoreSpecies) { - _currentMarkings.FilterSpecies(_currentSpecies, _markingManager); + _currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager); } // walk backwards through the list for visual purposes @@ -305,7 +311,7 @@ public sealed partial class MarkingPicker : Control var speciesPrototype = _prototypeManager.Index(species); _currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager); - _currentMarkings.FilterSpecies(species); + _currentMarkings.EnsureSpecies(species, null, _markingManager); Populate(); PopulateUsed(); @@ -335,7 +341,7 @@ public sealed partial class MarkingPicker : Control _selectedMarking = CMarkingsUsed[item.ItemIndex]; var prototype = (MarkingPrototype) _selectedMarking.Metadata!; - if (prototype.FollowSkinColor) + if (prototype.ForcedColoring) { CMarkingColors.Visible = false; @@ -412,12 +418,40 @@ public sealed partial class MarkingPicker : Control } var marking = (MarkingPrototype) _selectedUnusedMarking.Metadata!; - - var markingObject = marking.AsMarking(); - for (var i = 0; i < markingObject.MarkingColors.Count; i++) + + // We need add hair markings in cloned set manually because _currentMarkings doesn't have it + var markingSet = new MarkingSet(_currentMarkings); + if (HairMarking != null) { - markingObject.SetColor(i, CurrentSkinColor); + markingSet.AddBack(MarkingCategories.Hair, HairMarking); + } + if (FacialHairMarking != null) + { + markingSet.AddBack(MarkingCategories.FacialHair, FacialHairMarking); + } + + if (!_markingManager.MustMatchSkin(_currentSpecies, marking.BodyPart, _prototypeManager)) + { + // Do default coloring + var colors = MarkingColoring.GetMarkingLayerColors( + marking, + CurrentSkinColor, + CurrentEyeColor, + markingSet + ); + for (var i = 0; i < colors.Count; i++) + { + markingObject.SetColor(i, colors[i]); + } + } + else + { + // Color everything in skin color + for (var i = 0; i < marking.Sprites.Count; i++) + { + markingObject.SetColor(i, CurrentSkinColor); + } } markingObject.Forced = Forced; diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index 397c194b0a..4330a87945 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -53,7 +53,7 @@ namespace Content.Client.Preferences.UI private readonly IEntityManager _entMan; private readonly IConfigurationManager _configurationManager; private readonly MarkingManager _markingManager; - + private LineEdit _ageEdit => CAgeEdit; private LineEdit _nameEdit => CNameEdit; private LineEdit _flavorTextEdit = null!; @@ -223,6 +223,7 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithHairColor(newColor.marking.MarkingColors[0])); + UpdateCMarkingsHair(); IsDirty = true; }; @@ -241,6 +242,7 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithFacialHairColor(newColor.marking.MarkingColors[0])); + UpdateCMarkingsFacialHair(); IsDirty = true; }; @@ -252,6 +254,7 @@ namespace Content.Client.Preferences.UI Profile.Appearance.WithHairStyleName(HairStyles.DefaultHairStyle) ); UpdateHairPickers(); + UpdateCMarkingsHair(); IsDirty = true; }; @@ -263,6 +266,7 @@ namespace Content.Client.Preferences.UI Profile.Appearance.WithFacialHairStyleName(HairStyles.DefaultFacialHairStyle) ); UpdateHairPickers(); + UpdateCMarkingsFacialHair(); IsDirty = true; }; @@ -282,7 +286,7 @@ namespace Content.Client.Preferences.UI ); UpdateHairPickers(); - + UpdateCMarkingsHair(); IsDirty = true; }; @@ -302,7 +306,7 @@ namespace Content.Client.Preferences.UI ); UpdateHairPickers(); - + UpdateCMarkingsFacialHair(); IsDirty = true; }; @@ -343,6 +347,7 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithEyeColor(newColor)); + CMarkings.CurrentEyeColor = Profile.Appearance.EyeColor; IsDirty = true; }; @@ -646,7 +651,7 @@ namespace Content.Client.Preferences.UI var color = SkinColor.HumanSkinTone((int) _skinColor.Value); CMarkings.CurrentSkinColor = color; - Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color)); + Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));// break; } case HumanoidSkinColor.Hues: @@ -746,8 +751,8 @@ namespace Content.Client.Preferences.UI Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences!.SelectedCharacter; CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex; - _needUpdatePreview = true; UpdateControls(); + _needUpdatePreview = true; } private void SetAge(int newAge) @@ -941,7 +946,9 @@ namespace Content.Client.Preferences.UI return; } - CMarkings.SetData(Profile.Appearance.Markings, Profile.Species, Profile.Appearance.SkinColor); + CMarkings.SetData(Profile.Appearance.Markings, Profile.Species, + Profile.Appearance.SkinColor, Profile.Appearance.EyeColor + ); } private void UpdateSpecies() @@ -990,7 +997,6 @@ namespace Content.Client.Preferences.UI { return; } - var hairMarking = Profile.Appearance.HairStyleId switch { HairStyles.DefaultHairStyle => new List(), @@ -1013,6 +1019,76 @@ namespace Content.Client.Preferences.UI 1); } + private void UpdateCMarkingsHair() + { + if (Profile == null) + { + return; + } + + // hair color + Color? hairColor = null; + if ( Profile.Appearance.HairStyleId != HairStyles.DefaultHairStyle && + _markingManager.Markings.TryGetValue(Profile.Appearance.HairStyleId, out var hairProto) + ) + { + if (_markingManager.CanBeApplied(Profile.Species, hairProto, _prototypeManager)) + { + if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, _prototypeManager)) + { + hairColor = Profile.Appearance.SkinColor; + } + else + { + hairColor = Profile.Appearance.HairColor; + } + } + } + if (hairColor != null) + { + CMarkings.HairMarking = new (Profile.Appearance.HairStyleId, new List() { hairColor.Value }); + } + else + { + CMarkings.HairMarking = null; + } + } + + private void UpdateCMarkingsFacialHair() + { + if (Profile == null) + { + return; + } + + // facial hair color + Color? facialHairColor = null; + if ( Profile.Appearance.FacialHairStyleId != HairStyles.DefaultFacialHairStyle && + _markingManager.Markings.TryGetValue(Profile.Appearance.FacialHairStyleId, out var facialHairProto) + ) + { + if (_markingManager.CanBeApplied(Profile.Species, facialHairProto, _prototypeManager)) + { + if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, _prototypeManager)) + { + facialHairColor = Profile.Appearance.SkinColor; + } + else + { + facialHairColor = Profile.Appearance.FacialHairColor; + } + } + } + if (facialHairColor != null) + { + CMarkings.FacialHairMarking = new (Profile.Appearance.FacialHairStyleId, new List() { facialHairColor.Value }); + } + else + { + CMarkings.FacialHairMarking = null; + } + } + private void UpdateEyePickers() { if (Profile == null) @@ -1020,6 +1096,7 @@ namespace Content.Client.Preferences.UI return; } + CMarkings.CurrentEyeColor = Profile.Appearance.EyeColor; _eyesPicker.SetData(Profile.Appearance.EyeColor); } @@ -1049,7 +1126,6 @@ namespace Content.Client.Preferences.UI UpdateClothingControls(); UpdateBackpackControls(); UpdateAgeEdit(); - UpdateHairPickers(); UpdateEyePickers(); UpdateSaveButton(); UpdateJobPriorities(); @@ -1057,6 +1133,9 @@ namespace Content.Client.Preferences.UI UpdateTraitPreferences(); UpdateMarkings(); RebuildSpriteView(); + UpdateHairPickers(); + UpdateCMarkingsHair(); + UpdateCMarkingsFacialHair(); _preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable); } diff --git a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs index ed83b7c189..669c1cb1b4 100644 --- a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs +++ b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs @@ -47,6 +47,7 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS } LoadProfile(uid, startingSet.Profile, humanoid); + } private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args) @@ -79,16 +80,56 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS humanoid.MarkingSet.Clear(); - // Hair/facial hair - this may eventually be deprecated. - - AddMarking(uid, profile.Appearance.HairStyleId, profile.Appearance.HairColor, false); - AddMarking(uid, profile.Appearance.FacialHairStyleId, profile.Appearance.FacialHairColor, false); - + // Add markings that doesn't need coloring. We store them until we add all other markings that doesn't need it. + var markingFColored = new Dictionary(); foreach (var marking in profile.Appearance.Markings) { - AddMarking(uid, marking.MarkingId, marking.MarkingColors, false); + if (_markingManager.TryGetMarking(marking, out var prototype)) + { + if (!prototype.ForcedColoring) + { + AddMarking(uid, marking.MarkingId, marking.MarkingColors, false); + } + else + { + markingFColored.Add(marking, prototype); + } + } } + // Hair/facial hair - this may eventually be deprecated. + // We need to ensure hair before applying it or coloring can try depend on markings that can be invalid + var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, _prototypeManager) + ? profile.Appearance.SkinColor : profile.Appearance.HairColor; + var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, _prototypeManager) + ? profile.Appearance.SkinColor : profile.Appearance.FacialHairColor; + + if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) && + _markingManager.CanBeApplied(profile.Species, hairPrototype, _prototypeManager)) + { + AddMarking(uid, profile.Appearance.HairStyleId, hairColor, false); + } + + if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) && + _markingManager.CanBeApplied(profile.Species, facialHairPrototype, _prototypeManager)) + { + AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false); + } + + humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager); + + // Finally adding marking with forced colors + foreach (var (marking, prototype) in markingFColored) + { + var markingColors = MarkingColoring.GetMarkingLayerColors( + prototype, + profile.Appearance.SkinColor, + profile.Appearance.EyeColor, + humanoid.MarkingSet + ); + AddMarking(uid, marking.MarkingId, markingColors, false); + } + EnsureDefaultMarkings(uid, humanoid); humanoid.Gender = profile.Gender; @@ -336,7 +377,6 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS { return; } - - humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, _markingManager); + humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, humanoid.EyeColor, _markingManager); } } diff --git a/Content.Server/Humanoid/Systems/HumanoidSystem.Modifier.cs b/Content.Server/Humanoid/Systems/HumanoidSystem.Modifier.cs index bcd65d77be..cd5cbda318 100644 --- a/Content.Server/Humanoid/Systems/HumanoidSystem.Modifier.cs +++ b/Content.Server/Humanoid/Systems/HumanoidSystem.Modifier.cs @@ -36,7 +36,10 @@ public sealed partial class HumanoidAppearanceSystem _uiSystem.TrySetUiState( uid, HumanoidMarkingModifierKey.Key, - new HumanoidMarkingModifierState(component.MarkingSet, component.Species, component.SkinColor, component.CustomBaseLayers)); + new HumanoidMarkingModifierState(component.MarkingSet, component.Species, + component.SkinColor, + component.CustomBaseLayers + )); } }); } @@ -66,7 +69,10 @@ public sealed partial class HumanoidAppearanceSystem _uiSystem.TrySetUiState( uid, HumanoidMarkingModifierKey.Key, - new HumanoidMarkingModifierState(component.MarkingSet, component.Species, component.SkinColor, component.CustomBaseLayers)); + new HumanoidMarkingModifierState(component.MarkingSet, component.Species, + component.SkinColor, + component.CustomBaseLayers + )); } } @@ -87,7 +93,10 @@ public sealed partial class HumanoidAppearanceSystem _uiSystem.TrySetUiState( uid, HumanoidMarkingModifierKey.Key, - new HumanoidMarkingModifierState(component.MarkingSet, component.Species, component.SkinColor, component.CustomBaseLayers)); + new HumanoidMarkingModifierState(component.MarkingSet, component.Species, + component.SkinColor, + component.CustomBaseLayers + )); } } diff --git a/Content.Server/MagicMirror/MagicMirrorSystem.cs b/Content.Server/MagicMirror/MagicMirrorSystem.cs index c242b0b936..90a0b19b7d 100644 --- a/Content.Server/MagicMirror/MagicMirrorSystem.cs +++ b/Content.Server/MagicMirror/MagicMirrorSystem.cs @@ -177,4 +177,4 @@ public sealed class MagicMirrorSystem : EntitySystem UpdateInterface(uid, args.User, args.Session); } -} +} \ No newline at end of file diff --git a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs index 35c713d5e1..35444842cb 100644 --- a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs +++ b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs @@ -70,6 +70,18 @@ public sealed class HumanoidAppearanceComponent : Component [DataField("eyeColor")] public Color EyeColor = Color.Brown; + + /// + /// Hair color of this humanoid. Used to avoid looping through all markings + /// + [ViewVariables(VVAccess.ReadOnly)] + public Color? CachedHairColor; + + /// + /// Facial Hair color of this humanoid. Used to avoid looping through all markings + /// + [ViewVariables(VVAccess.ReadOnly)] + public Color? CachedFacialHairColor; } [Serializable, NetSerializable] diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs index 6c03ec746c..5d000fd270 100644 --- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs @@ -217,7 +217,6 @@ namespace Content.Shared.Humanoid { markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto); markingSet.EnsureValid(markingManager); - markingSet.FilterSpecies(species, markingManager); switch (speciesProto.SkinColoration) { @@ -236,6 +235,7 @@ namespace Content.Shared.Humanoid break; } + markingSet.EnsureSpecies(species, skinColor, markingManager); } return new HumanoidCharacterAppearance( diff --git a/Content.Shared/Humanoid/HumanoidVisualLayers.cs b/Content.Shared/Humanoid/HumanoidVisualLayers.cs index 5d587f982c..938b789f7a 100644 --- a/Content.Shared/Humanoid/HumanoidVisualLayers.cs +++ b/Content.Shared/Humanoid/HumanoidVisualLayers.cs @@ -1,4 +1,5 @@ -using Robust.Shared.Serialization; +using Content.Shared.Humanoid.Markings; +using Robust.Shared.Serialization; namespace Content.Shared.Humanoid { diff --git a/Content.Shared/Humanoid/Markings/ColoringTypes/CategoryColoring.cs b/Content.Shared/Humanoid/Markings/ColoringTypes/CategoryColoring.cs new file mode 100644 index 0000000000..1ed3e531ff --- /dev/null +++ b/Content.Shared/Humanoid/Markings/ColoringTypes/CategoryColoring.cs @@ -0,0 +1,24 @@ +using System.Linq; + +namespace Content.Shared.Humanoid.Markings; + +/// +/// Colors marking in color of first defined marking from specified category (in e.x. from Hair category) +/// +public sealed class CategoryColoring : LayerColoringType +{ + [DataField("category", required: true)] + public MarkingCategories Category; + + public override Color? GetCleanColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + Color? outColor = null; + if (markingSet.TryGetCategory(Category, out var markings) && + markings.Count > 0) + { + outColor = markings[0].MarkingColors.FirstOrDefault(); + } + + return outColor; + } +} diff --git a/Content.Shared/Humanoid/Markings/ColoringTypes/EyeColoring.cs b/Content.Shared/Humanoid/Markings/ColoringTypes/EyeColoring.cs new file mode 100644 index 0000000000..0c7865418b --- /dev/null +++ b/Content.Shared/Humanoid/Markings/ColoringTypes/EyeColoring.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Humanoid.Markings; + +/// +/// Colors layer in an eye color +/// +public sealed class EyeColoring : LayerColoringType +{ + public override Color? GetCleanColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + return eyes; + } +} diff --git a/Content.Shared/Humanoid/Markings/ColoringTypes/SimpleColoring.cs b/Content.Shared/Humanoid/Markings/ColoringTypes/SimpleColoring.cs new file mode 100644 index 0000000000..2ee68b88c3 --- /dev/null +++ b/Content.Shared/Humanoid/Markings/ColoringTypes/SimpleColoring.cs @@ -0,0 +1,15 @@ +namespace Content.Shared.Humanoid.Markings; + +/// +/// Colors layer in a specified color +/// +public sealed class SimpleColoring : LayerColoringType +{ + [DataField("color", required: true)] + public Color Color = Color.White; + + public override Color? GetCleanColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + return Color; + } +} diff --git a/Content.Shared/Humanoid/Markings/ColoringTypes/SkinColoring.cs b/Content.Shared/Humanoid/Markings/ColoringTypes/SkinColoring.cs new file mode 100644 index 0000000000..49cdb7985c --- /dev/null +++ b/Content.Shared/Humanoid/Markings/ColoringTypes/SkinColoring.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Humanoid.Markings; + +/// +/// Colors layer in a skin color +/// +public sealed class SkinColoring : LayerColoringType +{ + public override Color? GetCleanColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + return skin; + } +} diff --git a/Content.Shared/Humanoid/Markings/ColoringTypes/TattooColoring.cs b/Content.Shared/Humanoid/Markings/ColoringTypes/TattooColoring.cs new file mode 100644 index 0000000000..225ad67da3 --- /dev/null +++ b/Content.Shared/Humanoid/Markings/ColoringTypes/TattooColoring.cs @@ -0,0 +1,20 @@ +namespace Content.Shared.Humanoid.Markings; + +/// +/// Colors layer in skin color but much darker. +/// +public sealed class TattooColoring : LayerColoringType +{ + public override Color? GetCleanColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + if (skin == null) + { + return null; + } + + var newColor = Color.ToHsv(skin.Value); + newColor.Z = .40f; + + return Color.FromHsv(newColor); + } +} diff --git a/Content.Shared/Humanoid/Markings/Marking.cs b/Content.Shared/Humanoid/Markings/Marking.cs index 25413da91e..c7d5cb6184 100644 --- a/Content.Shared/Humanoid/Markings/Marking.cs +++ b/Content.Shared/Humanoid/Markings/Marking.cs @@ -1,4 +1,6 @@ using System.Linq; +using Content.Shared.Humanoid.Prototypes; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Humanoid.Markings @@ -67,6 +69,14 @@ namespace Content.Shared.Humanoid.Markings public void SetColor(int colorIndex, Color color) => _markingColors[colorIndex] = color; + public void SetColor(Color color) + { + for (int i = 0; i < _markingColors.Count; i++) + { + _markingColors[i] = color; + } + } + public int CompareTo(Marking? marking) { if (marking == null) diff --git a/Content.Shared/Humanoid/Markings/MarkingColoring.cs b/Content.Shared/Humanoid/Markings/MarkingColoring.cs new file mode 100644 index 0000000000..d90fdec0c7 --- /dev/null +++ b/Content.Shared/Humanoid/Markings/MarkingColoring.cs @@ -0,0 +1,147 @@ +using Robust.Shared.Utility; + +namespace Content.Shared.Humanoid.Markings; + +/// +/// Default colors for marking +/// +[DataDefinition] +public sealed class MarkingColors +{ + /// + /// Coloring properties that will be used on any unspecified layer + /// + [DataField("default", true)] + public LayerColoringDefinition Default = new LayerColoringDefinition(); + + /// + /// Layers with their own coloring type and properties + /// + [DataField("layers", true)] + public Dictionary? Layers; +} + +public static class MarkingColoring +{ + /// + /// Returns list of colors for marking layers + /// + public static List GetMarkingLayerColors + ( + MarkingPrototype prototype, + Color? skinColor, + Color? eyeColor, + MarkingSet markingSet + ) + { + var colors = new List(); + + // Coloring from default properties + var defaultColor = prototype.Coloring.Default.GetColor(skinColor, eyeColor, markingSet); + + if (prototype.Coloring.Layers == null) + { + // If layers is not specified, then every layer must be default + for (var i = 0; i < prototype.Sprites.Count; i++) + { + colors.Add(defaultColor); + } + return colors; + } + else + { + // If some layers are specified. + for (var i = 0; i < prototype.Sprites.Count; i++) + { + // Getting layer name + string? name = prototype.Sprites[i] switch + { + SpriteSpecifier.Rsi rsi => rsi.RsiState, + SpriteSpecifier.Texture texture => texture.TexturePath.Filename, + _ => null + }; + if (name == null) + { + colors.Add(defaultColor); + continue; + } + + // All specified layers must be colored separately, all unspecified must depend on default coloring + if (prototype.Coloring.Layers.TryGetValue(name, out var layerColoring)) + { + var marking_color = layerColoring.GetColor(skinColor, eyeColor, markingSet); + colors.Add(marking_color); + } + else + { + colors.Add(defaultColor); + } + } + return colors; + } + } +} + +/// +/// A class that defines coloring type and fallback for markings +/// +[DataDefinition] +public sealed class LayerColoringDefinition +{ + [DataField("type")] + public LayerColoringType Type = new SkinColoring(); + + /// + /// Coloring types that will be used if main coloring type will return nil + /// + [DataField("fallbackTypes")] + public List FallbackTypes = new() {}; + + /// + /// Color that will be used if coloring type and fallback type will return nil + /// + [DataField("fallbackColor")] + public Color FallbackColor = Color.White; + + public Color GetColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + var color = Type.GetColor(skin, eyes, markingSet); + if (color == null) + { + foreach (var type in FallbackTypes) + { + color = type.GetColor(skin, eyes, markingSet); + if (color != null) break; + } + } + return color ?? FallbackColor; + } +} + +/// +/// An abstract class for coloring types +/// +[ImplicitDataDefinitionForInheritors] +public abstract class LayerColoringType +{ + /// + /// Makes output color negative + /// + [DataField("negative")] + public bool Negative { get; } = false; + public abstract Color? GetCleanColor(Color? skin, Color? eyes, MarkingSet markingSet); + public Color? GetColor(Color? skin, Color? eyes, MarkingSet markingSet) + { + var color = GetCleanColor(skin, eyes, markingSet); + // Negative color + if (color != null && Negative) + { + var rcolor = color.Value; + rcolor.R = 1f-rcolor.R; + rcolor.G = 1f-rcolor.G; + rcolor.B = 1f-rcolor.B; + return rcolor; + } + return color; + } +} \ No newline at end of file diff --git a/Content.Shared/Humanoid/Markings/MarkingManager.cs b/Content.Shared/Humanoid/Markings/MarkingManager.cs index b1f4477c3d..08a721d345 100644 --- a/Content.Shared/Humanoid/Markings/MarkingManager.cs +++ b/Content.Shared/Humanoid/Markings/MarkingManager.cs @@ -120,5 +120,69 @@ namespace Content.Shared.Humanoid.Markings _index.Add(markingPrototype); } } + + public bool CanBeApplied(string species, Marking marking, IPrototypeManager? prototypeManager = null) + { + IoCManager.Resolve(ref prototypeManager); + + var speciesProto = prototypeManager.Index(species); + var onlyWhitelisted = prototypeManager.Index(speciesProto.MarkingPoints).OnlyWhitelisted; + + if (!TryGetMarking(marking, out var prototype)) + { + return false; + } + + if (onlyWhitelisted && prototype.SpeciesRestrictions == null) + { + return false; + } + + if (prototype.SpeciesRestrictions != null + && !prototype.SpeciesRestrictions.Contains(species)) + { + return false; + } + return true; + } + + public bool CanBeApplied(string species, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null) + { + IoCManager.Resolve(ref prototypeManager); + + var speciesProto = prototypeManager.Index(species); + var onlyWhitelisted = prototypeManager.Index(speciesProto.MarkingPoints).OnlyWhitelisted; + + if (onlyWhitelisted && prototype.SpeciesRestrictions == null) + { + return false; + } + + if (prototype.SpeciesRestrictions != null && + !prototype.SpeciesRestrictions.Contains(species)) + { + return false; + } + return true; + } + + public bool MustMatchSkin(string species, HumanoidVisualLayers layer, IPrototypeManager? prototypeManager = null) + { + IoCManager.Resolve(ref prototypeManager); + + var speciesProto = prototypeManager.Index(species); + if ( + !prototypeManager.TryIndex(speciesProto.SpriteSet, out HumanoidSpeciesBaseSpritesPrototype? baseSprites) || + !baseSprites.Sprites.TryGetValue(layer, out var spriteName) || + !prototypeManager.TryIndex(spriteName, out HumanoidSpeciesSpriteLayer? sprite) || + sprite == null || + !sprite.MarkingsMatchSkin + ) + { + return false; + } + + return true; + } } } diff --git a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs index bda78f6421..3ceb319761 100644 --- a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs +++ b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs @@ -16,13 +16,19 @@ namespace Content.Shared.Humanoid.Markings [DataField("markingCategory", required: true)] public MarkingCategories MarkingCategory { get; } = default!; - + [DataField("speciesRestriction")] public List? SpeciesRestrictions { get; } [DataField("followSkinColor")] public bool FollowSkinColor { get; } = false; + [DataField("forcedColoring")] + public bool ForcedColoring { get; } = false; + + [DataField("coloring")] + public MarkingColors Coloring { get; } = new(); + [DataField("sprites", required: true)] public List Sprites { get; private set; } = default!; diff --git a/Content.Shared/Humanoid/Markings/MarkingsSet.cs b/Content.Shared/Humanoid/Markings/MarkingsSet.cs index 4a6a5163ff..9535e28e1a 100644 --- a/Content.Shared/Humanoid/Markings/MarkingsSet.cs +++ b/Content.Shared/Humanoid/Markings/MarkingsSet.cs @@ -4,6 +4,7 @@ using System.Linq; using Content.Shared.Humanoid.Prototypes; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared.Humanoid.Markings; @@ -104,6 +105,22 @@ public sealed class MarkingSet } } + /// + /// Construct a MarkingSet only with a points dictionary. + /// + /// The ID of the points dictionary prototype. + public MarkingSet(string pointsPrototype, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) + { + IoCManager.Resolve(ref markingManager, ref prototypeManager); + + if (!prototypeManager.TryIndex(pointsPrototype, out MarkingPointsPrototype? points)) + { + return; + } + + Points = MarkingPoints.CloneMarkingPointDictionary(points.Points); + } + /// /// Construct a MarkingSet by deep cloning another set. /// @@ -122,12 +139,13 @@ public sealed class MarkingSet } /// - /// Filters markings based on species restrictions in the marking's prototype from this marking set. + /// Filters and colors markings based on species and it's restrictions in the marking's prototype from this marking set. /// /// The species to filter. + /// The skin color for recoloring (i.e. slimes). Use null if you want only filter markings /// Marking manager. /// Prototype manager. - public void FilterSpecies(string species, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) + public void EnsureSpecies(string species, Color? skinColor, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) { IoCManager.Resolve(ref markingManager); IoCManager.Resolve(ref prototypeManager); @@ -163,6 +181,22 @@ public sealed class MarkingSet { Remove(remove.category, remove.id); } + + // Re-color left markings them into skin color if needed (i.e. for slimes) + if (skinColor != null) + { + foreach (var (category, list) in Markings) + { + foreach (var marking in list) + { + if (markingManager.TryGetMarking(marking, out var prototype) && + markingManager.MustMatchSkin(species, prototype.BodyPart, prototypeManager)) + { + marking.SetColor(skinColor.Value); + } + } + } + } } /// @@ -200,9 +234,11 @@ public sealed class MarkingSet /// /// Ensures that the default markings as defined by the marking point set in this marking set are applied. /// - /// Color to apply. + /// Skin color for marking coloring. + /// Eye color for marking coloring. + /// Hair color for marking coloring. /// Marking manager. - public void EnsureDefault(Color? skinColor = null, MarkingManager? markingManager = null) + public void EnsureDefault(Color? skinColor = null, Color? eyeColor = null, MarkingManager? markingManager = null) { IoCManager.Resolve(ref markingManager); @@ -218,22 +254,13 @@ public sealed class MarkingSet { if (markingManager.Markings.TryGetValue(points.DefaultMarkings[index], out var prototype)) { - Marking marking; - if (skinColor == null) - { - marking = new Marking(points.DefaultMarkings[index], prototype.Sprites.Count); - } - else - { - var colors = new List(); - - for (var i = 0; i < prototype.Sprites.Count; i++) - { - colors.Add(skinColor.Value); - } - - marking = new Marking(points.DefaultMarkings[index], colors); - } + var colors = MarkingColoring.GetMarkingLayerColors( + prototype, + skinColor, + eyeColor, + this + ); + var marking = new Marking(points.DefaultMarkings[index], colors); AddBack(category, marking); } diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index e803313a10..4f436bbf40 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -129,7 +129,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem } humanoid.Species = species; - humanoid.MarkingSet.FilterSpecies(species, _markingManager); + humanoid.MarkingSet.EnsureSpecies(species, humanoid.SkinColor, _markingManager); var oldMarkings = humanoid.MarkingSet.GetForwardEnumerator().ToList(); humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager); diff --git a/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs b/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs index 9f8c7d6712..0c0dfc3174 100644 --- a/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs @@ -42,7 +42,12 @@ public sealed class HumanoidMarkingModifierBaseLayersSetMessage : BoundUserInter public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState { // TODO just use the component state, remove the BUI state altogether. - public HumanoidMarkingModifierState(MarkingSet markingSet, string species, Color skinColor, Dictionary customBaseLayers) + public HumanoidMarkingModifierState( + MarkingSet markingSet, + string species, + Color skinColor, + Dictionary customBaseLayers + ) { MarkingSet = markingSet; Species = species; @@ -53,5 +58,8 @@ public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState public MarkingSet MarkingSet { get; } public string Species { get; } public Color SkinColor { get; } + public Color EyeColor { get; } + public Color? HairColor { get; } + public Color? FacialHairColor { get; } public Dictionary CustomBaseLayers { get; } } diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/cat_parts.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/cat_parts.yml index d779d71bd3..de88a17fd7 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/cat_parts.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/cat_parts.yml @@ -3,6 +3,18 @@ bodyPart: HeadTop markingCategory: HeadTop speciesRestriction: [Human] + coloring: + default: + type: + !type:CategoryColoring + category: Hair + fallbackTypes: + - !type:SkinColoring + layers: + ears_cat_inner: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/cat_parts.rsi state: ears_cat_outer @@ -14,6 +26,15 @@ bodyPart: Tail markingCategory: Tail speciesRestriction: [Human] + coloring: + default: + type: + !type:CategoryColoring + category: Hair + fallbackTypes: + - !type:CategoryColoring + category: FacialHair + - !type:SkinColoring sprites: - sprite: Mobs/Customization/cat_parts.rsi state: tail_cat diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/diona.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/diona.yml index bf417b7569..0db9994eff 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/diona.yml @@ -3,6 +3,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: thorns_head @@ -12,6 +17,11 @@ bodyPart: Chest markingCategory: Chest speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: thorns_body @@ -21,6 +31,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: flowers_head @@ -30,6 +45,11 @@ bodyPart: Chest markingCategory: Chest speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: flowers_body @@ -39,6 +59,10 @@ bodyPart: Chest markingCategory: Chest speciesRestriction: [Diona] + coloring: + default: + type: + !type:SkinColoring sprites: - sprite: Mobs/Customization/diona.rsi state: leaf_cover @@ -48,6 +72,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: bloom @@ -57,6 +86,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: bracket @@ -66,6 +100,10 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SkinColoring sprites: - sprite: Mobs/Customization/diona.rsi state: brush @@ -75,6 +113,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: cornflower @@ -84,6 +127,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: ficus @@ -93,6 +141,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: garland @@ -102,6 +155,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: king @@ -111,6 +169,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: laurel @@ -120,6 +183,11 @@ bodyPart: HeadTop markingCategory: HeadTop speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: leafy @@ -129,6 +197,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: lotus @@ -138,6 +211,11 @@ bodyPart: HeadTop markingCategory: HeadTop speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: meadow @@ -147,6 +225,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: oak @@ -156,6 +239,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: palm @@ -165,6 +253,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: root @@ -174,6 +267,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: rose @@ -183,6 +281,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: rosey @@ -192,6 +295,11 @@ bodyPart: HeadTop markingCategory: HeadTop speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: shrub @@ -201,6 +309,11 @@ bodyPart: HeadSide markingCategory: HeadSide speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: spinner @@ -210,6 +323,11 @@ bodyPart: HeadSide markingCategory: HeadSide speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: sprout @@ -219,6 +337,11 @@ bodyPart: HeadTop markingCategory: HeadTop speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: vine @@ -228,6 +351,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: vinel @@ -237,6 +365,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: vines @@ -246,6 +379,11 @@ bodyPart: Head markingCategory: Head speciesRestriction: [Diona] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" sprites: - sprite: Mobs/Customization/diona.rsi state: wildflower diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml index 8c24e82cea..81e23f406f 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml @@ -157,7 +157,7 @@ id: LizardSnoutRound bodyPart: Snout markingCategory: Snout - followSkinColor: true + forcedColoring: true speciesRestriction: [Reptilian] sprites: - sprite: Mobs/Customization/reptilian_parts.rsi @@ -167,7 +167,7 @@ id: LizardSnoutSharp bodyPart: Snout markingCategory: Snout - followSkinColor: true + forcedColoring: true speciesRestriction: [Reptilian] sprites: - sprite: Mobs/Customization/reptilian_parts.rsi @@ -177,8 +177,7 @@ id: LizardChestTiger bodyPart: Chest markingCategory: Chest - followSkinColor: false speciesRestriction: [Reptilian] sprites: - sprite: Mobs/Customization/reptilian_parts.rsi - state: body_tiger \ No newline at end of file + state: body_tiger diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/tattoos.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/tattoos.yml index 3b2991134b..dffaa25984 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/tattoos.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/tattoos.yml @@ -3,6 +3,11 @@ bodyPart: Chest markingCategory: Chest speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_hive_chest @@ -12,6 +17,11 @@ bodyPart: Chest markingCategory: Chest speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_nightling @@ -21,6 +31,11 @@ bodyPart: LLeg markingCategory: Legs speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_silverburgh_l_leg @@ -30,6 +45,11 @@ bodyPart: RLeg markingCategory: Legs speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_silverburgh_r_leg @@ -39,6 +59,11 @@ bodyPart: LArm markingCategory: Arms speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_campbell_l_arm @@ -48,6 +73,11 @@ bodyPart: RArm markingCategory: Arms speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_campbell_r_arm @@ -57,6 +87,11 @@ bodyPart: LLeg markingCategory: Legs speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_campbell_l_leg @@ -66,6 +101,11 @@ bodyPart: RLeg markingCategory: Legs speciesRestriction: [Human] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_campbell_r_leg @@ -75,6 +115,11 @@ bodyPart: Eyes markingCategory: Head speciesRestriction: [Human, SlimePerson, Reptilian] + coloring: + default: + type: + !type:EyeColoring + negative: true sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_eye_r @@ -84,6 +129,11 @@ bodyPart: Eyes markingCategory: Head speciesRestriction: [Human, SlimePerson, Reptilian] + coloring: + default: + type: + !type:EyeColoring + negative: true sprites: - sprite: Mobs/Customization/tattoos.rsi state: tattoo_eye_l