Scurret naming fixes (#38776)

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
This commit is contained in:
Hannah Giovanna Dawson
2025-07-06 23:30:44 +01:00
committed by GitHub
parent 575694e5b5
commit f5fd2dcb76
6 changed files with 112 additions and 30 deletions

View File

@@ -20,7 +20,7 @@ public sealed class NameIdentifierSystem : EntitySystem
/// Free IDs available per <see cref="NameIdentifierGroupPrototype"/>. /// Free IDs available per <see cref="NameIdentifierGroupPrototype"/>.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public readonly Dictionary<string, List<int>> CurrentIds = new(); public readonly Dictionary<string, List<int>> CurrentIds = [];
public override void Initialize() public override void Initialize()
{ {
@@ -35,18 +35,22 @@ public sealed class NameIdentifierSystem : EntitySystem
InitialSetupPrototypes(); InitialSetupPrototypes();
} }
private void OnComponentShutdown(EntityUid uid, NameIdentifierComponent component, ComponentShutdown args) private void OnComponentShutdown(Entity<NameIdentifierComponent> ent, ref ComponentShutdown args)
{ {
if (CurrentIds.TryGetValue(component.Group, out var ids)) if (ent.Comp.Group is null)
return;
if (CurrentIds.TryGetValue(ent.Comp.Group, out var ids) && ids.Count > 0)
{ {
// Avoid inserting the value right back at the end or shuffling in place: // Avoid inserting the value right back at the end or shuffling in place:
// just pick a random spot to put it and then move that one to the end. // just pick a random spot to put it and then move that one to the end.
var randomIndex = _robustRandom.Next(ids.Count); var randomIndex = _robustRandom.Next(ids.Count);
var random = ids[randomIndex]; var random = ids[randomIndex];
ids[randomIndex] = component.Identifier; ids[randomIndex] = ent.Comp.Identifier;
ids.Add(random); ids.Add(random);
} }
_nameModifier.RefreshNameModifiers(uid);
_nameModifier.RefreshNameModifiers(ent.Owner);
} }
/// <summary> /// <summary>
@@ -83,46 +87,53 @@ public sealed class NameIdentifierSystem : EntitySystem
: $"{randomVal}"; : $"{randomVal}";
} }
private void OnMapInit(EntityUid uid, NameIdentifierComponent component, MapInitEvent args) private void OnMapInit(Entity<NameIdentifierComponent> ent, ref MapInitEvent args)
{ {
if (!_prototypeManager.TryIndex<NameIdentifierGroupPrototype>(component.Group, out var group)) if (ent.Comp.Group is null)
return;
if (!_prototypeManager.TryIndex(ent.Comp.Group, out var group))
return; return;
int id; int id;
string uniqueName; string uniqueName;
// If it has an existing valid identifier then use that, otherwise generate a new one. // If it has an existing valid identifier then use that, otherwise generate a new one.
if (component.Identifier != -1 && if (ent.Comp.Identifier != -1 &&
CurrentIds.TryGetValue(component.Group, out var ids) && CurrentIds.TryGetValue(ent.Comp.Group, out var ids) &&
ids.Remove(component.Identifier)) ids.Remove(ent.Comp.Identifier))
{ {
id = component.Identifier; id = ent.Comp.Identifier;
uniqueName = group.Prefix is not null uniqueName = group.Prefix is not null
? $"{group.Prefix}-{id}" ? $"{group.Prefix}-{id}"
: $"{id}"; : $"{id}";
} }
else else
{ {
uniqueName = GenerateUniqueName(uid, group, out id); uniqueName = GenerateUniqueName(ent, group, out id);
component.Identifier = id; ent.Comp.Identifier = id;
} }
component.FullIdentifier = group.FullName ent.Comp.FullIdentifier = group.FullName
? uniqueName ? uniqueName
: $"({uniqueName})"; : $"({uniqueName})";
Dirty(uid, component); Dirty(ent);
_nameModifier.RefreshNameModifiers(uid); _nameModifier.RefreshNameModifiers(ent.Owner);
} }
private void OnRefreshNameModifiers(Entity<NameIdentifierComponent> ent, ref RefreshNameModifiersEvent args) private void OnRefreshNameModifiers(Entity<NameIdentifierComponent> ent, ref RefreshNameModifiersEvent args)
{ {
if (ent.Comp.Group is null)
return;
// Don't apply the modifier if the component is being removed // Don't apply the modifier if the component is being removed
if (ent.Comp.LifeStage > ComponentLifeStage.Running) if (ent.Comp.LifeStage > ComponentLifeStage.Running)
return; return;
if (!_prototypeManager.TryIndex<NameIdentifierGroupPrototype>(ent.Comp.Group, out var group)) if (!_prototypeManager.TryIndex(ent.Comp.Group, out var group))
return; return;
var format = group.FullName ? "name-identifier-format-full" : "name-identifier-format-append"; var format = group.FullName ? "name-identifier-format-full" : "name-identifier-format-append";
// We apply the modifier with a low priority to keep it near the base name // We apply the modifier with a low priority to keep it near the base name
// "Beep (Si-4562) the zombie" instead of "Beep the zombie (Si-4562)" // "Beep (Si-4562) the zombie" instead of "Beep the zombie (Si-4562)"
@@ -188,13 +199,13 @@ public sealed class NameIdentifierSystem : EntitySystem
foreach (var proto in set.Modified.Values) foreach (var proto in set.Modified.Values)
{ {
var name_proto = (NameIdentifierGroupPrototype) proto; var name_proto = (NameIdentifierGroupPrototype)proto;
// Only bother adding new ones. // Only bother adding new ones.
if (CurrentIds.ContainsKey(proto.ID)) if (CurrentIds.ContainsKey(proto.ID))
continue; continue;
var ids = GetOrCreateIdList(name_proto); var ids = GetOrCreateIdList(name_proto);
FillGroup(name_proto, ids); FillGroup(name_proto, ids);
} }
} }

View File

@@ -1,5 +1,5 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Prototypes;
namespace Content.Shared.NameIdentifier; namespace Content.Shared.NameIdentifier;
@@ -9,18 +9,18 @@ namespace Content.Shared.NameIdentifier;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class NameIdentifierComponent : Component public sealed partial class NameIdentifierComponent : Component
{ {
[DataField("group", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<NameIdentifierGroupPrototype>))] [DataField]
public string Group = string.Empty; public ProtoId<NameIdentifierGroupPrototype>? Group;
/// <summary> /// <summary>
/// The randomly generated ID for this entity. /// The randomly generated ID for this entity.
/// </summary> /// </summary>
[DataField("identifier"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] [DataField, AutoNetworkedField]
public int Identifier = -1; public int Identifier = -1;
/// <summary> /// <summary>
/// The full name identifier for this entity. /// The full name identifier for this entity.
/// </summary> /// </summary>
[DataField("fullIdentifier"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] [DataField, AutoNetworkedField]
public string FullIdentifier = string.Empty; public string FullIdentifier = string.Empty;
} }

View File

@@ -1,3 +1,19 @@
# Scurrets from Planet Wawa have two parts to their name - a 'chosen' and 'qualitative' name.
# The chosen name is picked by the scurret themselves,
# encompassing a trait or value they hold themselves
# to or have a high value for. Scurrets sometimes change this
# name to denote an important moment in their life.
# It appears to be common for scurret sets to share the same
# chosen name, with the gaining of a pup's own chosen name
# signalling their transition to adulthood in the community.
# Given the scurret language is untranslated, these names are
# usually guessed via charades or Pictionary.
# When all else fails, to NT and her crews, Wa is as good a name as any.
names-scurret-first-dataset-1 = Wa names-scurret-first-dataset-1 = Wa
names-scurret-first-dataset-2 = Calm names-scurret-first-dataset-2 = Calm
names-scurret-first-dataset-3 = Contented names-scurret-first-dataset-3 = Contented
@@ -34,3 +50,18 @@ names-scurret-first-dataset-33 = Wise
names-scurret-first-dataset-34 = Alert names-scurret-first-dataset-34 = Alert
names-scurret-first-dataset-35 = Uplifting names-scurret-first-dataset-35 = Uplifting
names-scurret-first-dataset-36 = Considerate names-scurret-first-dataset-36 = Considerate
names-scurret-first-dataset-37 = Surviving
names-scurret-first-dataset-38 = Meditating
names-scurret-first-dataset-39 = Hunting
names-scurret-first-dataset-40 = Watching
names-scurret-first-dataset-41 = Resting
names-scurret-first-dataset-42 = Delivering
names-scurret-first-dataset-43 = Swimming
names-scurret-first-dataset-44 = Swinging
names-scurret-first-dataset-45 = Exploding
names-scurret-first-dataset-46 = Romancing
names-scurret-first-dataset-47 = Far-Seeing
names-scurret-first-dataset-48 = Loyal
names-scurret-first-dataset-49 = Inquisitive
# After consulting with lawyers, NT added this one to the dictionary.
names-scurret-first-dataset-50 = Legally Distinct

View File

@@ -1,3 +1,19 @@
# Scurrets from Planet Wawa have two parts to their name - a 'chosen' and 'qualitative' name.
# The qualitative name is usually related to an important feature
# of Wawa's wetland habitats that the scurret is associated with
# by their community.
# Scurret pups, due to both their quantity and complete lack
# of any survival instinct, lack a qualitative name entirely.
# Researchers believe their parents simply give them a number.
# Given that the scurret language is untranslated, these names are
# usually deduced via the showing of photographs, annoyed and
# repeated pointing at nearby objects, or games of Pictionary.
# When all else fails, to NT and her crews, Wa is as good a name as any.
names-scurret-last-dataset-1 = Wa names-scurret-last-dataset-1 = Wa
names-scurret-last-dataset-2 = Trees names-scurret-last-dataset-2 = Trees
names-scurret-last-dataset-3 = Plants names-scurret-last-dataset-3 = Plants
@@ -6,12 +22,12 @@ names-scurret-last-dataset-5 = Rivers
names-scurret-last-dataset-6 = Groves names-scurret-last-dataset-6 = Groves
names-scurret-last-dataset-7 = Lakes names-scurret-last-dataset-7 = Lakes
names-scurret-last-dataset-8 = Marshes names-scurret-last-dataset-8 = Marshes
names-scurret-last-dataset-9 = Spring names-scurret-last-dataset-9 = Springs
names-scurret-last-dataset-10 = Reeds names-scurret-last-dataset-10 = Reeds
names-scurret-last-dataset-11 = Sunshine names-scurret-last-dataset-11 = Sunshine
names-scurret-last-dataset-12 = Rain names-scurret-last-dataset-12 = Rain
names-scurret-last-dataset-13 = Clouds names-scurret-last-dataset-13 = Clouds
names-scurret-last-dataset-14 = Snowfall names-scurret-last-dataset-14 = Snowfalls
names-scurret-last-dataset-15 = Stones names-scurret-last-dataset-15 = Stones
names-scurret-last-dataset-16 = Pebbles names-scurret-last-dataset-16 = Pebbles
names-scurret-last-dataset-17 = Fishes names-scurret-last-dataset-17 = Fishes
@@ -25,7 +41,7 @@ names-scurret-last-dataset-24 = Alders
names-scurret-last-dataset-25 = Birches names-scurret-last-dataset-25 = Birches
names-scurret-last-dataset-26 = Poplars names-scurret-last-dataset-26 = Poplars
names-scurret-last-dataset-27 = Marigolds names-scurret-last-dataset-27 = Marigolds
names-scurret-last-dataset-28 = Robins names-scurret-last-dataset-28 = Rowans
names-scurret-last-dataset-29 = Orchids names-scurret-last-dataset-29 = Orchids
names-scurret-last-dataset-30 = Rushes names-scurret-last-dataset-30 = Rushes
names-scurret-last-dataset-31 = Lillies names-scurret-last-dataset-31 = Lillies
@@ -33,4 +49,20 @@ names-scurret-last-dataset-32 = Violets
names-scurret-last-dataset-33 = Maples names-scurret-last-dataset-33 = Maples
names-scurret-last-dataset-34 = Oaks names-scurret-last-dataset-34 = Oaks
names-scurret-last-dataset-35 = Hazels names-scurret-last-dataset-35 = Hazels
# AND SIR GIDEON OFNIR
names-scurret-last-dataset-36 = the All-Knowing names-scurret-last-dataset-36 = the All-Knowing
names-scurret-last-dataset-37 = Tarns
names-scurret-last-dataset-38 = Waters
names-scurret-last-dataset-39 = Reservoirs
names-scurret-last-dataset-40 = Dams
names-scurret-last-dataset-41 = Moors
names-scurret-last-dataset-42 = Fens
names-scurret-last-dataset-43 = Temples
names-scurret-last-dataset-44 = Hills
names-scurret-last-dataset-45 = Copses
names-scurret-last-dataset-46 = Fields
names-scurret-last-dataset-47 = Ancestors
names-scurret-last-dataset-48 = Forests
names-scurret-last-dataset-49 = Secrets
# Nobody's quite sure how this one is in the dictionary.
names-scurret-last-dataset-50 = Space Ferret

View File

@@ -2,10 +2,10 @@
id: NamesFirstScurret id: NamesFirstScurret
values: values:
prefix: names-scurret-first-dataset- prefix: names-scurret-first-dataset-
count: 36 count: 50
- type: localizedDataset - type: localizedDataset
id: NamesLastScurret id: NamesLastScurret
values: values:
prefix: names-scurret-last-dataset- prefix: names-scurret-last-dataset-
count: 36 count: 50

View File

@@ -139,6 +139,14 @@
available: available:
- enum.DamageStateVisualLayers.Base: - enum.DamageStateVisualLayers.Base:
scurret: ScurretColors scurret: ScurretColors
# They are of a mysterious gender.
- type: Grammar
attributes:
gender: epicene
proper: true
# Strips the name identifier from them, so they're just "Confident Waters" rather than "Confident Waters (123)"
- type: NameIdentifier
group: null
# Emotional Support Scurrets have a ghost role and equipment. At the moment, these are intended to be used for admemes, but # Emotional Support Scurrets have a ghost role and equipment. At the moment, these are intended to be used for admemes, but
# feel free to hook them into random content. # feel free to hook them into random content.
@@ -169,4 +177,4 @@
name: Emotional Support Scurret name: Emotional Support Scurret
id: MobEmotionalSupportScurret id: MobEmotionalSupportScurret
parent: [MobScurret, MobBaseEmotionalSupportScurret] parent: [MobScurret, MobBaseEmotionalSupportScurret]
description: Commonly known as Wawa, from the wetlands of Planet Wawa, these critters make up the bulk of Arnolds's Pizza's "loyal workforce". This one is here as a temp. description: Commonly known as Wawa, from the wetlands of Planet Wawa, these critters make up the bulk of Arnold's Pizza's "loyal workforce". This one is here as a temp.