Let species prototypes define valid sexes (Sex Refactor) (#11520)

This commit is contained in:
Rane
2022-10-15 17:45:47 -04:00
committed by GitHub
parent 0e18ba567c
commit c70e423ff6
14 changed files with 161 additions and 97 deletions

View 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);
}
}
}

View File

@@ -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

View File

@@ -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,
}
}

View File

@@ -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);

View File

@@ -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.