]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Sex restriction for markings (#19894)
authorMorb <14136326+Morb0@users.noreply.github.com>
Tue, 19 Sep 2023 20:56:10 +0000 (23:56 +0300)
committerGitHub <noreply@github.com>
Tue, 19 Sep 2023 20:56:10 +0000 (16:56 -0400)
* Add sex restriction to markings

* Apply to existing systems

13 files changed:
Content.Client/Humanoid/HumanoidAppearanceSystem.cs
Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs
Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs
Content.Client/Humanoid/MarkingPicker.xaml.cs
Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs
Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs
Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
Content.Shared/Humanoid/Markings/MarkingManager.cs
Content.Shared/Humanoid/Markings/MarkingPrototype.cs
Content.Shared/Humanoid/Markings/MarkingsSet.cs
Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs
Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs
Content.Shared/Preferences/HumanoidCharacterProfile.cs

index 76f1aaaec8a54ad5b3fe109e40b5263ebdad7c4b..0b37844c6ee219ab0e9be4655a76cf4db00c4bab 100644 (file)
@@ -170,11 +170,11 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
         var facialHair = new Marking(profile.Appearance.FacialHairStyleId,
             new[] { facialHairColor });
 
-        if (_markingManager.CanBeApplied(profile.Species, hair, _prototypeManager))
+        if (_markingManager.CanBeApplied(profile.Species, profile.Sex, hair, _prototypeManager))
         {
             markings.AddBack(MarkingCategories.Hair, hair);
         }
-        if (_markingManager.CanBeApplied(profile.Species, facialHair, _prototypeManager))
+        if (_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHair, _prototypeManager))
         {
             markings.AddBack(MarkingCategories.FacialHair, facialHair);
         }
@@ -192,6 +192,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
         }
 
         markings.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager);
+        markings.EnsureSexes(profile.Sex, _markingManager);
         markings.EnsureDefault(
             profile.Appearance.SkinColor,
             profile.Appearance.EyeColor,
index 286965f8b2771bc5a19701addc7e6351a239cb53..a1742219fb044de95c8afc2babecc6c4cf0e07d5 100644 (file)
@@ -42,7 +42,7 @@ public sealed class HumanoidMarkingModifierBoundUserInterface : BoundUserInterfa
             return;
         }
 
-        _window.SetState(cast.MarkingSet, cast.Species, cast.SkinColor, cast.CustomBaseLayers);
+        _window.SetState(cast.MarkingSet, cast.Species, cast.Sex, cast.SkinColor, cast.CustomBaseLayers);
     }
 
     private void SendMarkingSet(MarkingSet set)
index ea39c501b3dda468f7868d8fd3085364d7c657d4..8cf90c4e63a3da895ba35e7b35ad15f7835d1055 100644 (file)
@@ -63,6 +63,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
     public void SetState(
         MarkingSet markings,
         string species,
+        Sex sex,
         Color skinColor,
         Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> info
     )
@@ -84,7 +85,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
             eyesColor = eyes.Color.Value;
         }
 
-        MarkingPickerWidget.SetData(markings, species, skinColor, eyesColor);
+        MarkingPickerWidget.SetData(markings, species, sex, skinColor, eyesColor);
     }
 
     private sealed class HumanoidBaseLayerModifier : BoxContainer
index 9df4e28655443c6d458f7b91889d5b45868bf094..43333439f08c4a712a9c9bc3d1623666df9f262b 100644 (file)
@@ -35,6 +35,7 @@ public sealed partial class MarkingPicker : Control
     private List<MarkingCategories> _markingCategories = Enum.GetValues<MarkingCategories>().ToList();
 
     private string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies;
+    private Sex _currentSex = Sex.Unsexed;
     public Color CurrentSkinColor = Color.White;
     public Color CurrentEyeColor = Color.Black;
     public Marking? HairMarking;
@@ -77,7 +78,7 @@ public sealed partial class MarkingPicker : Control
         }
     }
 
-    public void SetData(List<Marking> newMarkings, string species, Color skinColor, Color eyeColor)
+    public void SetData(List<Marking> newMarkings, string species, Sex sex, Color skinColor, Color eyeColor)
     {
         var pointsProto = _prototypeManager
             .Index<SpeciesPrototype>(species).MarkingPoints;
@@ -89,6 +90,7 @@ public sealed partial class MarkingPicker : Control
         }
 
         _currentSpecies = species;
+        _currentSex = sex;
         CurrentSkinColor = skinColor;
         CurrentEyeColor = eyeColor;
 
@@ -96,7 +98,7 @@ public sealed partial class MarkingPicker : Control
         PopulateUsed();
     }
 
-    public void SetData(MarkingSet set, string species, Color skinColor, Color eyeColor)
+    public void SetData(MarkingSet set, string species, Sex sex, Color skinColor, Color eyeColor)
     {
         _currentMarkings = set;
 
@@ -106,6 +108,7 @@ public sealed partial class MarkingPicker : Control
         }
 
         _currentSpecies = species;
+        _currentSex = sex;
         CurrentSkinColor = skinColor;
         CurrentEyeColor = eyeColor;
 
@@ -182,8 +185,8 @@ public sealed partial class MarkingPicker : Control
         _selectedUnusedMarking = null;
 
         var markings = IgnoreSpecies
-            ? _markingManager.MarkingsByCategory(_selectedMarkingCategory)
-            : _markingManager.MarkingsByCategoryAndSpecies(_selectedMarkingCategory, _currentSpecies);
+            ? _markingManager.MarkingsByCategoryAndSex(_selectedMarkingCategory, _currentSex)
+            : _markingManager.MarkingsByCategoryAndSpeciesAndSex(_selectedMarkingCategory, _currentSpecies, _currentSex);
 
         var sortedMarkings = markings.Values.Where(m =>
             m.ID.ToLower().Contains(filter.ToLower()) ||
@@ -319,6 +322,22 @@ public sealed partial class MarkingPicker : Control
 
         _currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
         _currentMarkings.EnsureSpecies(species, null, _markingManager);
+        _currentMarkings.EnsureSexes(_currentSex, _markingManager);
+
+        Populate(CMarkingSearch.Text);
+        PopulateUsed();
+    }
+
+    public void SetSex(Sex sex)
+    {
+        _currentSex = sex;
+        var markingList = _currentMarkings.GetForwardEnumerator().ToList();
+
+        var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(_currentSpecies);
+
+        _currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
+        _currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager);
+        _currentMarkings.EnsureSexes(_currentSex, _markingManager);
 
         Populate(CMarkingSearch.Text);
         PopulateUsed();
index 59ce6fe8fceee5542d6ca2fb31cc2cc440d6e975..59e08d344f8d9c20182ce8fac6151f92d81f522c 100644 (file)
@@ -748,6 +748,7 @@ namespace Content.Client.Preferences.UI
                     break;
             }
             UpdateGenderControls();
+            CMarkings.SetSex(newSex);
             IsDirty = true;
         }
 
@@ -917,7 +918,7 @@ namespace Content.Client.Preferences.UI
             }
 
             CMarkings.SetData(Profile.Appearance.Markings, Profile.Species,
-                Profile.Appearance.SkinColor, Profile.Appearance.EyeColor
+                Profile.Sex, Profile.Appearance.SkinColor, Profile.Appearance.EyeColor
             );
         }
 
@@ -1002,7 +1003,7 @@ namespace Content.Client.Preferences.UI
                 _markingManager.Markings.TryGetValue(Profile.Appearance.HairStyleId, out var hairProto)
             )
             {
-                if (_markingManager.CanBeApplied(Profile.Species, hairProto, _prototypeManager))
+                if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, hairProto, _prototypeManager))
                 {
                     if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager))
                     {
@@ -1037,7 +1038,7 @@ namespace Content.Client.Preferences.UI
                 _markingManager.Markings.TryGetValue(Profile.Appearance.FacialHairStyleId, out var facialHairProto)
             )
             {
-                if (_markingManager.CanBeApplied(Profile.Species, facialHairProto, _prototypeManager))
+                if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, facialHairProto, _prototypeManager))
                 {
                     if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager))
                     {
index e7c421d0922d41af396573dbea744e87e040c05a..7c0bb7383b9c68af7b93f5031cb391c719585e6d 100644 (file)
@@ -37,6 +37,7 @@ public sealed partial class HumanoidAppearanceSystem
                     uid,
                     HumanoidMarkingModifierKey.Key,
                     new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
+                        component.Sex,
                         component.SkinColor,
                         component.CustomBaseLayers
                     ));
@@ -70,6 +71,7 @@ public sealed partial class HumanoidAppearanceSystem
                 uid,
                 HumanoidMarkingModifierKey.Key,
                 new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
+                        component.Sex,
                         component.SkinColor,
                         component.CustomBaseLayers
                     ));
@@ -94,6 +96,7 @@ public sealed partial class HumanoidAppearanceSystem
                 uid,
                 HumanoidMarkingModifierKey.Key,
                 new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
+                        component.Sex,
                         component.SkinColor,
                         component.CustomBaseLayers
                     ));
index e50e55025cf9b2e0d0c5e4b526eb4036274d3278..1ffcd1870be50841576cdd778587c46c0696befb 100644 (file)
@@ -188,7 +188,7 @@ namespace Content.Shared.Humanoid
             return new(color.RByte, color.GByte, color.BByte);
         }
 
-        public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species)
+        public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex)
         {
             var hairStyleId = appearance.HairStyleId;
             var facialHairStyleId = appearance.FacialHairStyleId;
@@ -223,6 +223,7 @@ namespace Content.Shared.Humanoid
                 }
 
                 markingSet.EnsureSpecies(species, skinColor, markingManager);
+                markingSet.EnsureSexes(sex, markingManager);
             }
 
             return new HumanoidCharacterAppearance(
index 9a72f5eebcf38955e1c9ede4a166c11b2b17ae38..68f7cfe362d548464377ef8843fe16f85256c81e 100644 (file)
@@ -66,6 +66,74 @@ namespace Content.Shared.Humanoid.Markings
                 {
                     continue;
                 }
+                res.Add(key, marking);
+            }
+
+            return res;
+        }
+
+        /// <summary>
+        ///     Markings by category and sex.
+        /// </summary>
+        /// <param name="category"></param>
+        /// <param name="sex"></param>
+        /// <remarks>
+        ///     This is done per category, as enumerating over every single marking by species isn't useful.
+        ///     Please make a pull request if you find a use case for that behavior.
+        /// </remarks>
+        /// <returns></returns>
+        public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSex(MarkingCategories category,
+            Sex sex)
+        {
+            var res = new Dictionary<string, MarkingPrototype>();
+
+            foreach (var (key, marking) in MarkingsByCategory(category))
+            {
+                if (marking.SexRestriction != null && marking.SexRestriction != sex)
+                {
+                    continue;
+                }
+
+                res.Add(key, marking);
+            }
+
+            return res;
+        }
+
+        /// <summary>
+        ///     Markings by category, species and sex.
+        /// </summary>
+        /// <param name="category"></param>
+        /// <param name="species"></param>
+        /// <param name="sex"></param>
+        /// <remarks>
+        ///     This is done per category, as enumerating over every single marking by species isn't useful.
+        ///     Please make a pull request if you find a use case for that behavior.
+        /// </remarks>
+        /// <returns></returns>
+        public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSpeciesAndSex(MarkingCategories category,
+            string species, Sex sex)
+        {
+            var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species);
+            var onlyWhitelisted = _prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted;
+            var res = new Dictionary<string, MarkingPrototype>();
+
+            foreach (var (key, marking) in MarkingsByCategory(category))
+            {
+                if (onlyWhitelisted && marking.SpeciesRestrictions == null)
+                {
+                    continue;
+                }
+
+                if (marking.SpeciesRestrictions != null && !marking.SpeciesRestrictions.Contains(species))
+                {
+                    continue;
+                }
+
+                if (marking.SexRestriction != null && marking.SexRestriction != sex)
+                {
+                    continue;
+                }
 
                 res.Add(key, marking);
             }
@@ -84,8 +152,9 @@ namespace Content.Shared.Humanoid.Markings
         /// <param name="marking"></param>
         /// <param name="category"></param>
         /// <param name="species"></param>
+        /// <param name="sex"></param>
         /// <returns></returns>
-        public bool IsValidMarking(Marking marking, MarkingCategories category, string species)
+        public bool IsValidMarking(Marking marking, MarkingCategories category, string species, Sex sex)
         {
             if (!TryGetMarking(marking, out var proto))
             {
@@ -93,7 +162,8 @@ namespace Content.Shared.Humanoid.Markings
             }
 
             if (proto.MarkingCategory != category ||
-                proto.SpeciesRestrictions != null && !proto.SpeciesRestrictions.Contains(species))
+                proto.SpeciesRestrictions != null && !proto.SpeciesRestrictions.Contains(species) ||
+                proto.SexRestriction != null && proto.SexRestriction != sex)
             {
                 return false;
             }
@@ -121,7 +191,7 @@ namespace Content.Shared.Humanoid.Markings
             }
         }
 
-        public bool CanBeApplied(string species, Marking marking, IPrototypeManager? prototypeManager = null)
+        public bool CanBeApplied(string species, Sex sex, Marking marking, IPrototypeManager? prototypeManager = null)
         {
             IoCManager.Resolve(ref prototypeManager);
 
@@ -143,10 +213,16 @@ namespace Content.Shared.Humanoid.Markings
             {
                 return false;
             }
+
+            if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
+            {
+                return false;
+            }
+
             return true;
         }
 
-        public bool CanBeApplied(string species, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null)
+        public bool CanBeApplied(string species, Sex sex, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null)
         {
             IoCManager.Resolve(ref prototypeManager);
 
@@ -163,6 +239,12 @@ namespace Content.Shared.Humanoid.Markings
             {
                 return false;
             }
+
+            if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
+            {
+                return false;
+            }
+
             return true;
         }
 
@@ -181,7 +263,7 @@ namespace Content.Shared.Humanoid.Markings
                 alpha = 1f;
                 return false;
             }
-            
+
             alpha = sprite.LayerAlpha;
             return true;
         }
index 14eb4e0d75c418c2d155435a35385b1e4738a710..19cb1773c9c3d735e434112fe5ca3bbbfc26b44a 100644 (file)
@@ -20,6 +20,9 @@ namespace Content.Shared.Humanoid.Markings
         [DataField("speciesRestriction")]
         public List<string>? SpeciesRestrictions { get; private set; }
 
+        [DataField("sexRestriction")]
+        public Sex? SexRestriction { get; private set; }
+
         [DataField("followSkinColor")]
         public bool FollowSkinColor { get; private set; } = false;
 
index 3fc6942600a3e0076831e0603ff48005b798f71a..d389e1941504162d1d56f7b2ac24cb21edfb35a0 100644 (file)
@@ -199,6 +199,40 @@ public sealed partial class MarkingSet
         }
     }
 
+    /// <summary>
+    ///     Filters markings based on sex and it's restrictions in the marking's prototype from this marking set.
+    /// </summary>
+    /// <param name="sex">The species to filter.</param>
+    /// <param name="markingManager">Marking manager.</param>
+    public void EnsureSexes(Sex sex, MarkingManager? markingManager = null)
+    {
+        IoCManager.Resolve(ref markingManager);
+
+        var toRemove = new List<(MarkingCategories category, string id)>();
+
+        foreach (var (category, list) in Markings)
+        {
+            foreach (var marking in list)
+            {
+                if (!markingManager.TryGetMarking(marking, out var prototype))
+                {
+                    toRemove.Add((category, marking.MarkingId));
+                    continue;
+                }
+
+                if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
+                {
+                    toRemove.Add((category, marking.MarkingId));
+                }
+            }
+        }
+
+        foreach (var remove in toRemove)
+        {
+            Remove(remove.category, remove.id);
+        }
+    }
+
     /// <summary>
     ///     Ensures that all markings in this set are valid.
     /// </summary>
index a4e3393c7e7f8b1b16b96166a0ad206491c0873b..e7e7b5a67281bec460af233ecdba163c66adec53 100644 (file)
@@ -254,6 +254,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
 
         var oldSex = humanoid.Sex;
         humanoid.Sex = sex;
+        humanoid.MarkingSet.EnsureSexes(sex, _markingManager);
         RaiseLocalEvent(uid, new SexChangedEvent(oldSex, sex));
 
         if (sync)
@@ -308,13 +309,13 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
             ? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor;
 
         if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) &&
-            _markingManager.CanBeApplied(profile.Species, hairPrototype, _prototypeManager))
+            _markingManager.CanBeApplied(profile.Species, profile.Sex, 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))
+            _markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _prototypeManager))
         {
             AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false);
         }
index 0c0dfc3174fb4584bc003229b13493965b60dc0b..bd0bad96703690b1045951512424f4ddc05d52b0 100644 (file)
@@ -45,18 +45,21 @@ public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState
     public HumanoidMarkingModifierState(
         MarkingSet markingSet,
         string species,
+        Sex sex,
         Color skinColor,
         Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayers
     )
     {
         MarkingSet = markingSet;
         Species = species;
+        Sex = sex;
         SkinColor = skinColor;
         CustomBaseLayers = customBaseLayers;
     }
 
     public MarkingSet MarkingSet { get; }
     public string Species { get; }
+    public Sex Sex { get; }
     public Color SkinColor { get; }
     public Color EyeColor { get; }
     public Color? HairColor { get; }
index a7369844336fd27056f6c10b0c53ca079af0471e..de5ef762320be96ed942876a9a8606e2ce7c0814 100644 (file)
@@ -433,7 +433,7 @@ namespace Content.Shared.Preferences
                 flavortext = FormattedMessage.RemoveMarkup(FlavorText);
             }
 
-            var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species);
+            var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex);
 
             var prefsUnavailableMode = PreferenceUnavailable switch
             {