Let species prototypes define valid sexes (Sex Refactor) (#11520)
This commit is contained in:
58
Content.Shared/Humanoid/NamingSystem.cs
Normal file
58
Content.Shared/Humanoid/NamingSystem.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Dataset;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
namespace Content.Shared.Humanoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Figure out how to name a humanoid with these extensions.
|
||||
/// </summary>
|
||||
public sealed class NamingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public string GetName(string species, Gender? gender = null)
|
||||
{
|
||||
// if they have an old species or whatever just fall back to human I guess?
|
||||
// Some downstream is probably gonna have this eventually but then they can deal with fallbacks.
|
||||
if (!_prototypeManager.TryIndex(species, out SpeciesPrototype? speciesProto))
|
||||
{
|
||||
speciesProto = _prototypeManager.Index<SpeciesPrototype>("Human");
|
||||
Logger.Warning($"Unable to find species {species} for name, falling back to Human");
|
||||
}
|
||||
|
||||
switch (speciesProto.Naming)
|
||||
{
|
||||
case SpeciesNaming.FirstDashFirst:
|
||||
return $"{GetFirstName(speciesProto, gender)}-{GetFirstName(speciesProto, gender)}";
|
||||
case SpeciesNaming.FirstLast:
|
||||
default:
|
||||
return $"{GetFirstName(speciesProto, gender)} {GetLastName(speciesProto)}";
|
||||
}
|
||||
}
|
||||
|
||||
public string GetFirstName(SpeciesPrototype speciesProto, Gender? gender = null)
|
||||
{
|
||||
switch (gender)
|
||||
{
|
||||
case Gender.Male:
|
||||
return _random.Pick(_prototypeManager.Index<DatasetPrototype>(speciesProto.MaleFirstNames).Values);
|
||||
case Gender.Female:
|
||||
return _random.Pick(_prototypeManager.Index<DatasetPrototype>(speciesProto.FemaleFirstNames).Values);
|
||||
default:
|
||||
if (_random.Prob(0.5f))
|
||||
return _random.Pick(_prototypeManager.Index<DatasetPrototype>(speciesProto.MaleFirstNames).Values);
|
||||
else
|
||||
return _random.Pick(_prototypeManager.Index<DatasetPrototype>(speciesProto.FemaleFirstNames).Values);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLastName(SpeciesPrototype speciesProto)
|
||||
{
|
||||
return _random.Pick(_prototypeManager.Index<DatasetPrototype>(speciesProto.LastNames).Values);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,9 @@ public sealed class SpeciesPrototype : IPrototype
|
||||
|
||||
[DataField("naming")]
|
||||
public SpeciesNaming Naming { get; } = SpeciesNaming.FirstLast;
|
||||
|
||||
[DataField("sexes")]
|
||||
public List<Sex> Sexes { get; } = new List<Sex>(){ Sex.Male, Sex.Female };
|
||||
}
|
||||
|
||||
public enum SpeciesNaming : byte
|
||||
|
||||
@@ -5,58 +5,11 @@ using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared.Humanoid
|
||||
{
|
||||
// You need to update profile, profile editor, maybe voices and names if you want to expand this further.
|
||||
public enum Sex : byte
|
||||
{
|
||||
Male,
|
||||
Female
|
||||
}
|
||||
|
||||
public static class SexExtensions
|
||||
{
|
||||
public static string GetName(this Sex sex, string species, IPrototypeManager? prototypeManager = null, IRobustRandom? random = null)
|
||||
{
|
||||
IoCManager.Resolve(ref prototypeManager);
|
||||
IoCManager.Resolve(ref random);
|
||||
|
||||
// if they have an old species or whatever just fall back to human I guess?
|
||||
// Some downstream is probably gonna have this eventually but then they can deal with fallbacks.
|
||||
if (!prototypeManager.TryIndex(species, out SpeciesPrototype? speciesProto))
|
||||
{
|
||||
speciesProto = prototypeManager.Index<SpeciesPrototype>("Human");
|
||||
Logger.Warning($"Unable to find species {species} for name, falling back to Human");
|
||||
}
|
||||
|
||||
switch (speciesProto.Naming)
|
||||
{
|
||||
case SpeciesNaming.FirstDashFirst:
|
||||
return $"{GetFirstName(sex, speciesProto, prototypeManager, random)}-{GetFirstName(sex, speciesProto, prototypeManager, random)}";
|
||||
case SpeciesNaming.FirstLast:
|
||||
default:
|
||||
return $"{GetFirstName(sex, speciesProto, prototypeManager, random)} {GetLastName(sex, speciesProto, prototypeManager, random)}";
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFirstName(this Sex sex, SpeciesPrototype speciesProto, IPrototypeManager? protoManager = null, IRobustRandom? random = null)
|
||||
{
|
||||
IoCManager.Resolve(ref protoManager);
|
||||
IoCManager.Resolve(ref random);
|
||||
|
||||
switch (sex)
|
||||
{
|
||||
case Sex.Male:
|
||||
return random.Pick(protoManager.Index<DatasetPrototype>(speciesProto.MaleFirstNames).Values);
|
||||
case Sex.Female:
|
||||
return random.Pick(protoManager.Index<DatasetPrototype>(speciesProto.FemaleFirstNames).Values);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetLastName(this Sex sex, SpeciesPrototype speciesProto, IPrototypeManager? protoManager = null, IRobustRandom? random = null)
|
||||
{
|
||||
IoCManager.Resolve(ref protoManager);
|
||||
IoCManager.Resolve(ref random);
|
||||
return random.Pick(protoManager.Index<DatasetPrototype>(speciesProto.LastNames).Values);
|
||||
}
|
||||
Female,
|
||||
Unsexed,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,10 +171,15 @@ namespace Content.Shared.Preferences
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
var sex = random.Prob(0.5f) ? Sex.Male : Sex.Female;
|
||||
var sex = Sex.Unsexed;
|
||||
if (prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype))
|
||||
{
|
||||
sex = random.Pick(speciesPrototype.Sexes);
|
||||
}
|
||||
|
||||
var gender = sex == Sex.Male ? Gender.Male : Gender.Female;
|
||||
|
||||
var name = sex.GetName(species, prototypeManager, random);
|
||||
var name = GetName(species, gender);
|
||||
var age = random.Next(MinimumAge, MaximumAge);
|
||||
|
||||
return new HumanoidCharacterProfile(name, "", species, age, sex, gender, HumanoidCharacterAppearance.Random(species, sex), ClothingPreference.Jumpsuit, BackpackPreference.Backpack,
|
||||
@@ -351,13 +356,27 @@ namespace Content.Shared.Preferences
|
||||
{
|
||||
var age = Math.Clamp(Age, MinimumAge, MaximumAge);
|
||||
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
|
||||
prototypeManager.TryIndex<SpeciesPrototype>(Species, out var speciesPrototype);
|
||||
|
||||
var sex = Sex switch
|
||||
{
|
||||
Sex.Male => Sex.Male,
|
||||
Sex.Female => Sex.Female,
|
||||
Sex.Unsexed => Sex.Unsexed,
|
||||
_ => Sex.Male // Invalid enum values.
|
||||
};
|
||||
|
||||
// ensure the species can be that sex
|
||||
if (speciesPrototype != null)
|
||||
{
|
||||
if (!speciesPrototype.Sexes.Contains(sex))
|
||||
{
|
||||
sex = speciesPrototype.Sexes[0];
|
||||
}
|
||||
}
|
||||
|
||||
var gender = Gender switch
|
||||
{
|
||||
Gender.Epicene => Gender.Epicene,
|
||||
@@ -370,7 +389,7 @@ namespace Content.Shared.Preferences
|
||||
string name;
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
{
|
||||
name = Sex.GetName(Species);
|
||||
name = GetName(Species, gender);
|
||||
}
|
||||
else if (Name.Length > MaxNameLength)
|
||||
{
|
||||
@@ -399,7 +418,7 @@ namespace Content.Shared.Preferences
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = Sex.GetName(Species);
|
||||
name = GetName(Species, gender);
|
||||
}
|
||||
|
||||
string flavortext;
|
||||
@@ -436,8 +455,6 @@ namespace Content.Shared.Preferences
|
||||
_ => BackpackPreference.Backpack // Invalid enum values.
|
||||
};
|
||||
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
|
||||
var priorities = new Dictionary<string, JobPriority>(JobPriorities
|
||||
.Where(p => prototypeManager.HasIndex<JobPrototype>(p.Key) && p.Value switch
|
||||
{
|
||||
@@ -481,6 +498,14 @@ namespace Content.Shared.Preferences
|
||||
_traitPreferences.AddRange(traits);
|
||||
}
|
||||
|
||||
// sorry this is kind of weird and duplicated,
|
||||
/// working inside these non entity systems is a bit wack
|
||||
public static string GetName(string species, Gender gender)
|
||||
{
|
||||
var namingSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<NamingSystem>();
|
||||
return namingSystem.GetName(species, gender);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is HumanoidCharacterProfile other && MemberwiseEquals(other);
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class GeneralStationRecord
|
||||
/// </summary>
|
||||
/// <remarks>Sex should be placed in a medical record, not a general record.</remarks>
|
||||
[ViewVariables]
|
||||
public Gender Gender = Gender.Neuter;
|
||||
public Gender Gender = Gender.Epicene;
|
||||
|
||||
/// <summary>
|
||||
/// The priority to display this record at.
|
||||
|
||||
Reference in New Issue
Block a user