Humanoid fixes (#11538)
* humanoid sexmorph sprite restoration can't believe i broke sex/gender AGAIN * fixes default species appearances with no profile, tweaks randomization to no longer randomize species * A * fixes an oops #11494
This commit is contained in:
@@ -57,6 +57,7 @@ public sealed class HumanoidSystem : SharedHumanoidSystem
|
|||||||
profile.Species,
|
profile.Species,
|
||||||
customBaseLayers,
|
customBaseLayers,
|
||||||
profile.Appearance.SkinColor,
|
profile.Appearance.SkinColor,
|
||||||
|
profile.Sex,
|
||||||
new(), // doesn't exist yet
|
new(), // doesn't exist yet
|
||||||
markings.GetForwardEnumerator().ToList());
|
markings.GetForwardEnumerator().ToList());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ public sealed class HumanoidVisualizerSystem : VisualizerSystem<HumanoidComponen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dirty = data.SkinColor != component.SkinColor;
|
var dirty = data.SkinColor != component.SkinColor || data.Sex != component.Sex;
|
||||||
|
component.Sex = data.Sex;
|
||||||
|
|
||||||
if (data.CustomBaseLayerInfo.Count != 0)
|
if (data.CustomBaseLayerInfo.Count != 0)
|
||||||
{
|
{
|
||||||
dirty |= MergeCustomBaseSprites(uid, baseSprites.Sprites, data.CustomBaseLayerInfo, component);
|
dirty |= MergeCustomBaseSprites(uid, baseSprites.Sprites, data.CustomBaseLayerInfo, component);
|
||||||
@@ -442,6 +444,4 @@ public sealed class HumanoidVisualizerSystem : VisualizerSystem<HumanoidComponen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,8 +179,7 @@ public sealed partial class MarkingPicker : Control
|
|||||||
|
|
||||||
foreach (var marking in markings.Values)
|
foreach (var marking in markings.Values)
|
||||||
{
|
{
|
||||||
if (_currentMarkings.TryGetCategory(_selectedMarkingCategory, out var listing)
|
if (_currentMarkings.TryGetMarking(_selectedMarkingCategory, marking.ID, out _))
|
||||||
&& listing.Contains(marking.AsMarking()))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,4 @@ namespace Content.Server.CharacterAppearance.Components;
|
|||||||
public sealed class RandomHumanoidAppearanceComponent : Component
|
public sealed class RandomHumanoidAppearanceComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("randomizeName")] public bool RandomizeName = true;
|
[DataField("randomizeName")] public bool RandomizeName = true;
|
||||||
|
|
||||||
[DataField("ignoredSpecies", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<SpeciesPrototype>))]
|
|
||||||
public readonly HashSet<string> IgnoredSpecies = new();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public sealed partial class HumanoidSystem : SharedHumanoidSystem
|
|||||||
component.Species,
|
component.Species,
|
||||||
component.CustomBaseLayers,
|
component.CustomBaseLayers,
|
||||||
component.SkinColor,
|
component.SkinColor,
|
||||||
|
component.Sex,
|
||||||
component.AllHiddenLayers.ToList(),
|
component.AllHiddenLayers.ToList(),
|
||||||
component.CurrentMarkings.GetForwardEnumerator().ToList());
|
component.CurrentMarkings.GetForwardEnumerator().ToList());
|
||||||
}
|
}
|
||||||
@@ -50,19 +51,20 @@ public sealed partial class HumanoidSystem : SharedHumanoidSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSpecies(uid, humanoid.Species, false, humanoid);
|
if (string.IsNullOrEmpty(humanoid.Initial)
|
||||||
|
|| !_prototypeManager.TryIndex(humanoid.Initial, out HumanoidProfilePrototype? startingSet))
|
||||||
if (!string.IsNullOrEmpty(humanoid.Initial)
|
|
||||||
&& _prototypeManager.TryIndex(humanoid.Initial, out HumanoidProfilePrototype? startingSet))
|
|
||||||
{
|
{
|
||||||
// Do this first, because profiles currently do not support custom base layers
|
LoadProfile(uid, HumanoidCharacterProfile.DefaultWithSpecies(humanoid.Species), humanoid);
|
||||||
foreach (var (layer, info) in startingSet.CustomBaseLayers)
|
return;
|
||||||
{
|
|
||||||
humanoid.CustomBaseLayers.Add(layer, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadProfile(uid, startingSet.Profile, humanoid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do this first, because profiles currently do not support custom base layers
|
||||||
|
foreach (var (layer, info) in startingSet.CustomBaseLayers)
|
||||||
|
{
|
||||||
|
humanoid.CustomBaseLayers.Add(layer, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadProfile(uid, startingSet.Profile, humanoid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExamined(EntityUid uid, HumanoidComponent component, ExaminedEvent args)
|
private void OnExamined(EntityUid uid, HumanoidComponent component, ExaminedEvent args)
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ public sealed class RandomHumanoidAppearanceSystem : EntitySystem
|
|||||||
private void OnMapInit(EntityUid uid, RandomHumanoidAppearanceComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, RandomHumanoidAppearanceComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
// If we have an initial profile/base layer set, do not randomize this humanoid.
|
// If we have an initial profile/base layer set, do not randomize this humanoid.
|
||||||
if (TryComp(uid, out HumanoidComponent? humanoid) && !string.IsNullOrEmpty(humanoid.Initial))
|
if (!TryComp(uid, out HumanoidComponent? humanoid) || !string.IsNullOrEmpty(humanoid.Initial))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var profile = HumanoidCharacterProfile.Random(component.IgnoredSpecies);
|
var profile = HumanoidCharacterProfile.RandomWithSpecies(humanoid.Species);
|
||||||
|
|
||||||
_humanoid.LoadProfile(uid, profile);
|
_humanoid.LoadProfile(uid, profile, humanoid);
|
||||||
|
|
||||||
if (component.RandomizeName)
|
if (component.RandomizeName)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,6 +97,28 @@ namespace Content.Shared.Humanoid
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
_ => 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>
|
private static IReadOnlyList<Color> RealisticEyeColors = new List<Color>
|
||||||
{
|
{
|
||||||
Color.Brown,
|
Color.Brown,
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ public enum HumanoidVisualizerKey
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class HumanoidVisualizerData : ICloneable
|
public sealed class HumanoidVisualizerData : ICloneable
|
||||||
{
|
{
|
||||||
public HumanoidVisualizerData(string species, Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayerInfo, Color skinColor, List<HumanoidVisualLayers> layerVisibility, List<Marking> markings)
|
public HumanoidVisualizerData(string species, Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayerInfo, Color skinColor, Sex sex, List<HumanoidVisualLayers> layerVisibility, List<Marking> markings)
|
||||||
{
|
{
|
||||||
Species = species;
|
Species = species;
|
||||||
CustomBaseLayerInfo = customBaseLayerInfo;
|
CustomBaseLayerInfo = customBaseLayerInfo;
|
||||||
SkinColor = skinColor;
|
SkinColor = skinColor;
|
||||||
|
Sex = sex;
|
||||||
LayerVisibility = layerVisibility;
|
LayerVisibility = layerVisibility;
|
||||||
Markings = markings;
|
Markings = markings;
|
||||||
}
|
}
|
||||||
@@ -24,11 +25,12 @@ public sealed class HumanoidVisualizerData : ICloneable
|
|||||||
public string Species { get; }
|
public string Species { get; }
|
||||||
public Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> CustomBaseLayerInfo { get; }
|
public Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> CustomBaseLayerInfo { get; }
|
||||||
public Color SkinColor { get; }
|
public Color SkinColor { get; }
|
||||||
|
public Sex Sex { get; }
|
||||||
public List<HumanoidVisualLayers> LayerVisibility { get; }
|
public List<HumanoidVisualLayers> LayerVisibility { get; }
|
||||||
public List<Marking> Markings { get; }
|
public List<Marking> Markings { get; }
|
||||||
|
|
||||||
public object Clone()
|
public object Clone()
|
||||||
{
|
{
|
||||||
return new HumanoidVisualizerData(Species, new(CustomBaseLayerInfo), SkinColor, new(LayerVisibility), new(Markings));
|
return new HumanoidVisualizerData(Species, new(CustomBaseLayerInfo), SkinColor, Sex, new(LayerVisibility), new(Markings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,19 @@ public sealed class SpeciesPrototype : IPrototype
|
|||||||
[DataField("sprites")]
|
[DataField("sprites")]
|
||||||
public string SpriteSet { get; } = default!;
|
public string SpriteSet { get; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default skin tone for this species. This applies for non-human skin tones.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("defaultSkinTone")]
|
||||||
|
public Color DefaultSkinTone { get; } = Color.White;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default human skin tone for this species. This applies for human skin tones.
|
||||||
|
/// See <see cref="SkinColor.HumanSkinTone"/> for the valid range of skin tones.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("defaultHumanSkinTone")]
|
||||||
|
public int DefaultHumanSkinTone { get; } = 20;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The limit of body markings that you can place on this species.
|
/// The limit of body markings that you can place on this species.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ public abstract class SharedHumanoidSystem : EntitySystem
|
|||||||
string species,
|
string species,
|
||||||
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayer,
|
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayer,
|
||||||
Color skinColor,
|
Color skinColor,
|
||||||
|
Sex sex,
|
||||||
List<HumanoidVisualLayers> visLayers,
|
List<HumanoidVisualLayers> visLayers,
|
||||||
List<Marking> markings)
|
List<Marking> markings)
|
||||||
{
|
{
|
||||||
var data = new HumanoidVisualizerData(species, customBaseLayer, skinColor, visLayers, markings);
|
var data = new HumanoidVisualizerData(species, customBaseLayer, skinColor, sex, visLayers, markings);
|
||||||
|
|
||||||
// Locally raise an event for this, because there might be some systems interested
|
// Locally raise an event for this, because there might be some systems interested
|
||||||
// in this.
|
// in this.
|
||||||
|
|||||||
@@ -15,11 +15,10 @@ public static class SkinColor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a human skin tone based on a scale of 0 to 100.
|
/// Get a human skin tone based on a scale of 0 to 100. The value is clamped between 0 and 100.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tone">Skin tone. Valid range is 0 to 100, inclusive. 0 is gold/yellowish, 100 is dark brown.</param>
|
/// <param name="tone">Skin tone. Valid range is 0 to 100, inclusive. 0 is gold/yellowish, 100 is dark brown.</param>
|
||||||
/// <returns>A human skin tone.</returns>
|
/// <returns>A human skin tone.</returns>
|
||||||
/// <exception cref="ArgumentException">Exception if the value is under 0 or over 100.</exception>
|
|
||||||
public static Color HumanSkinTone(int tone)
|
public static Color HumanSkinTone(int tone)
|
||||||
{
|
{
|
||||||
// 0 - 100, 0 being gold/yellowish and 100 being dark
|
// 0 - 100, 0 being gold/yellowish and 100 being dark
|
||||||
@@ -31,10 +30,7 @@ public static class SkinColor
|
|||||||
// 20 is 25 - 20 - 100
|
// 20 is 25 - 20 - 100
|
||||||
// 100 is 25 - 100 - 20
|
// 100 is 25 - 100 - 20
|
||||||
|
|
||||||
if (tone < 0 || tone > 100)
|
tone = Math.Clamp(tone, 0, 100);
|
||||||
{
|
|
||||||
throw new ArgumentException("Skin tone value was under 0 or over 100.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var rangeOffset = tone - 20;
|
var rangeOffset = tone - 20;
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ namespace Content.Shared.Preferences
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the default humanoid character profile, using internal constant values.
|
||||||
|
/// Defaults to <see cref="SharedHumanoidSystem.DefaultSpecies"/> for the species.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public static HumanoidCharacterProfile Default()
|
public static HumanoidCharacterProfile Default()
|
||||||
{
|
{
|
||||||
return new(
|
return new(
|
||||||
@@ -120,6 +125,33 @@ namespace Content.Shared.Preferences
|
|||||||
new List<string>());
|
new List<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return a default character profile, based on species.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="species">The species to use in this default profile. The default species is <see cref="SharedHumanoidSystem.DefaultSpecies"/>.</param>
|
||||||
|
/// <returns>Humanoid character profile with default settings.</returns>
|
||||||
|
public static HumanoidCharacterProfile DefaultWithSpecies(string species = SharedHumanoidSystem.DefaultSpecies)
|
||||||
|
{
|
||||||
|
return new(
|
||||||
|
"John Doe",
|
||||||
|
"",
|
||||||
|
species,
|
||||||
|
MinimumAge,
|
||||||
|
Sex.Male,
|
||||||
|
Gender.Male,
|
||||||
|
HumanoidCharacterAppearance.DefaultWithSpecies(species),
|
||||||
|
ClothingPreference.Jumpsuit,
|
||||||
|
BackpackPreference.Backpack,
|
||||||
|
new Dictionary<string, JobPriority>
|
||||||
|
{
|
||||||
|
{SharedGameTicker.FallbackOverflowJob, JobPriority.High}
|
||||||
|
},
|
||||||
|
PreferenceUnavailableMode.SpawnAsOverflow,
|
||||||
|
new List<string>(),
|
||||||
|
new List<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This should eventually not be a visual change only.
|
||||||
public static HumanoidCharacterProfile Random(HashSet<string>? ignoredSpecies = null)
|
public static HumanoidCharacterProfile Random(HashSet<string>? ignoredSpecies = null)
|
||||||
{
|
{
|
||||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||||
@@ -130,6 +162,15 @@ namespace Content.Shared.Preferences
|
|||||||
.Where(x => ignoredSpecies == null ? x.RoundStart : x.RoundStart && !ignoredSpecies.Contains(x.ID))
|
.Where(x => ignoredSpecies == null ? x.RoundStart : x.RoundStart && !ignoredSpecies.Contains(x.ID))
|
||||||
.ToArray()
|
.ToArray()
|
||||||
).ID;
|
).ID;
|
||||||
|
|
||||||
|
return RandomWithSpecies(species);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HumanoidCharacterProfile RandomWithSpecies(string species = SharedHumanoidSystem.DefaultSpecies)
|
||||||
|
{
|
||||||
|
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||||
|
var random = IoCManager.Resolve<IRobustRandom>();
|
||||||
|
|
||||||
var sex = random.Prob(0.5f) ? Sex.Male : Sex.Female;
|
var sex = random.Prob(0.5f) ? Sex.Male : Sex.Female;
|
||||||
var gender = sex == Sex.Male ? Gender.Male : Gender.Female;
|
var gender = sex == Sex.Male ? Gender.Male : Gender.Female;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
roundStart: true
|
roundStart: true
|
||||||
prototype: MobReptilian
|
prototype: MobReptilian
|
||||||
sprites: MobReptilianSprites
|
sprites: MobReptilianSprites
|
||||||
|
defaultSkinTone: "#34a223"
|
||||||
markingLimits: MobReptilianMarkingLimits
|
markingLimits: MobReptilianMarkingLimits
|
||||||
dollPrototype: MobReptilianDummy
|
dollPrototype: MobReptilianDummy
|
||||||
skinColoration: Hues
|
skinColoration: Hues
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
roundStart: true
|
roundStart: true
|
||||||
prototype: MobSlimePerson
|
prototype: MobSlimePerson
|
||||||
sprites: MobSlimeSprites
|
sprites: MobSlimeSprites
|
||||||
|
defaultSkinTone: "#b8b8b8"
|
||||||
markingLimits: MobSlimeMarkingLimits
|
markingLimits: MobSlimeMarkingLimits
|
||||||
dollPrototype: MobSlimePersonDummy
|
dollPrototype: MobSlimePersonDummy
|
||||||
skinColoration: Hues
|
skinColoration: Hues
|
||||||
|
|||||||
Reference in New Issue
Block a user