| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- using System.Linq;
- using Content.Shared.Humanoid.Markings;
- using Content.Shared.Humanoid.Prototypes;
- using Robust.Shared.Prototypes;
- using Robust.Shared.Random;
- using Robust.Shared.Serialization;
- namespace Content.Shared.Humanoid;
- [DataDefinition]
- [Serializable, NetSerializable]
- public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance, IEquatable<HumanoidCharacterAppearance>
- {
- [DataField("hair")]
- public string HairStyleId { get; set; } = HairStyles.DefaultHairStyle;
- [DataField]
- public Color HairColor { get; set; } = Color.Black;
- [DataField("facialHair")]
- public string FacialHairStyleId { get; set; } = HairStyles.DefaultFacialHairStyle;
- [DataField]
- public Color FacialHairColor { get; set; } = Color.Black;
- [DataField]
- public Color EyeColor { get; set; } = Color.Black;
- [DataField]
- public Color SkinColor { get; set; } = Humanoid.SkinColor.ValidHumanSkinTone;
- [DataField]
- public List<Marking> Markings { get; set; } = new();
- public HumanoidCharacterAppearance(string hairStyleId,
- Color hairColor,
- string facialHairStyleId,
- Color facialHairColor,
- Color eyeColor,
- Color skinColor,
- List<Marking> markings)
- {
- HairStyleId = hairStyleId;
- HairColor = ClampColor(hairColor);
- FacialHairStyleId = facialHairStyleId;
- FacialHairColor = ClampColor(facialHairColor);
- EyeColor = ClampColor(eyeColor);
- SkinColor = ClampColor(skinColor);
- Markings = markings;
- }
- public HumanoidCharacterAppearance(HumanoidCharacterAppearance other) :
- this(other.HairStyleId, other.HairColor, other.FacialHairStyleId, other.FacialHairColor, other.EyeColor, other.SkinColor, new(other.Markings))
- {
- }
- public HumanoidCharacterAppearance WithHairStyleName(string newName)
- {
- return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings);
- }
- public HumanoidCharacterAppearance WithHairColor(Color newColor)
- {
- return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings);
- }
- public HumanoidCharacterAppearance WithFacialHairStyleName(string newName)
- {
- return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor, Markings);
- }
- public HumanoidCharacterAppearance WithFacialHairColor(Color newColor)
- {
- return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor, Markings);
- }
- public HumanoidCharacterAppearance WithEyeColor(Color newColor)
- {
- return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor, Markings);
- }
- public HumanoidCharacterAppearance WithSkinColor(Color newColor)
- {
- return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor, Markings);
- }
- public HumanoidCharacterAppearance WithMarkings(List<Marking> newMarkings)
- {
- return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, newMarkings);
- }
- public static HumanoidCharacterAppearance DefaultWithSpecies(string species)
- {
- var speciesPrototype = IoCManager.Resolve<IPrototypeManager>().Index<SpeciesPrototype>(species);
- var skinColor = speciesPrototype.SkinColoration switch
- {
- HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone),
- HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone,
- HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone),
- HumanoidSkinColor.VoxFeathers => Humanoid.SkinColor.ClosestVoxColor(speciesPrototype.DefaultSkinTone),
- _ => Humanoid.SkinColor.ValidHumanSkinTone,
- };
- return new(
- HairStyles.DefaultHairStyle,
- Color.Black,
- HairStyles.DefaultFacialHairStyle,
- Color.Black,
- Color.Black,
- skinColor,
- new ()
- );
- }
- private static IReadOnlyList<Color> RealisticEyeColors = new List<Color>
- {
- Color.Brown,
- Color.Gray,
- Color.Azure,
- Color.SteelBlue,
- Color.Black
- };
- public static HumanoidCharacterAppearance Random(string species, Sex sex)
- {
- var random = IoCManager.Resolve<IRobustRandom>();
- var markingManager = IoCManager.Resolve<MarkingManager>();
- var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList();
- var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species).Keys.ToList();
- var newHairStyle = hairStyles.Count > 0
- ? random.Pick(hairStyles)
- : HairStyles.DefaultHairStyle;
- var newFacialHairStyle = facialHairStyles.Count == 0 || sex == Sex.Female
- ? HairStyles.DefaultFacialHairStyle
- : random.Pick(facialHairStyles);
- var newHairColor = random.Pick(HairStyles.RealisticHairColors);
- newHairColor = newHairColor
- .WithRed(RandomizeColor(newHairColor.R))
- .WithGreen(RandomizeColor(newHairColor.G))
- .WithBlue(RandomizeColor(newHairColor.B));
- // TODO: Add random markings
- var newEyeColor = random.Pick(RealisticEyeColors);
- var skinType = IoCManager.Resolve<IPrototypeManager>().Index<SpeciesPrototype>(species).SkinColoration;
- var newSkinColor = new Color(random.NextFloat(1), random.NextFloat(1), random.NextFloat(1), 1);
- switch (skinType)
- {
- case HumanoidSkinColor.HumanToned:
- var tone = Math.Round(Humanoid.SkinColor.HumanSkinToneFromColor(newSkinColor));
- newSkinColor = Humanoid.SkinColor.HumanSkinTone((int)tone);
- break;
- case HumanoidSkinColor.Hues:
- break;
- case HumanoidSkinColor.TintedHues:
- newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(newSkinColor);
- break;
- case HumanoidSkinColor.VoxFeathers:
- newSkinColor = Humanoid.SkinColor.ProportionalVoxColor(newSkinColor);
- break;
- }
- return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ());
- float RandomizeColor(float channel)
- {
- return MathHelper.Clamp01(channel + random.Next(-25, 25) / 100f);
- }
- }
- public static Color ClampColor(Color color)
- {
- return new(color.RByte, color.GByte, color.BByte);
- }
- public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex)
- {
- var hairStyleId = appearance.HairStyleId;
- var facialHairStyleId = appearance.FacialHairStyleId;
- var hairColor = ClampColor(appearance.HairColor);
- var facialHairColor = ClampColor(appearance.FacialHairColor);
- var eyeColor = ClampColor(appearance.EyeColor);
- var proto = IoCManager.Resolve<IPrototypeManager>();
- var markingManager = IoCManager.Resolve<MarkingManager>();
- if (!markingManager.MarkingsByCategory(MarkingCategories.Hair).ContainsKey(hairStyleId))
- {
- hairStyleId = HairStyles.DefaultHairStyle;
- }
- if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId))
- {
- facialHairStyleId = HairStyles.DefaultFacialHairStyle;
- }
- var markingSet = new MarkingSet();
- var skinColor = appearance.SkinColor;
- if (proto.TryIndex(species, out SpeciesPrototype? speciesProto))
- {
- markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto);
- markingSet.EnsureValid(markingManager);
- if (!Humanoid.SkinColor.VerifySkinColor(speciesProto.SkinColoration, skinColor))
- {
- skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor);
- }
- markingSet.EnsureSpecies(species, skinColor, markingManager);
- markingSet.EnsureSexes(sex, markingManager);
- }
- return new HumanoidCharacterAppearance(
- hairStyleId,
- hairColor,
- facialHairStyleId,
- facialHairColor,
- eyeColor,
- skinColor,
- markingSet.GetForwardEnumerator().ToList());
- }
- public bool MemberwiseEquals(ICharacterAppearance maybeOther)
- {
- if (maybeOther is not HumanoidCharacterAppearance other) return false;
- if (HairStyleId != other.HairStyleId) return false;
- if (!HairColor.Equals(other.HairColor)) return false;
- if (FacialHairStyleId != other.FacialHairStyleId) return false;
- if (!FacialHairColor.Equals(other.FacialHairColor)) return false;
- if (!EyeColor.Equals(other.EyeColor)) return false;
- if (!SkinColor.Equals(other.SkinColor)) return false;
- if (!Markings.SequenceEqual(other.Markings)) return false;
- return true;
- }
- public bool Equals(HumanoidCharacterAppearance? other)
- {
- if (ReferenceEquals(null, other)) return false;
- if (ReferenceEquals(this, other)) return true;
- return HairStyleId == other.HairStyleId &&
- HairColor.Equals(other.HairColor) &&
- FacialHairStyleId == other.FacialHairStyleId &&
- FacialHairColor.Equals(other.FacialHairColor) &&
- EyeColor.Equals(other.EyeColor) &&
- SkinColor.Equals(other.SkinColor) &&
- Markings.SequenceEqual(other.Markings);
- }
- public override bool Equals(object? obj)
- {
- return ReferenceEquals(this, obj) || obj is HumanoidCharacterAppearance other && Equals(other);
- }
- public override int GetHashCode()
- {
- return HashCode.Combine(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings);
- }
- public HumanoidCharacterAppearance Clone()
- {
- return new(this);
- }
- }
|