diff --git a/Content.Server/Chemistry/Components/TransformableContainerComponent.cs b/Content.Server/Chemistry/Components/TransformableContainerComponent.cs
index 5ea9a24487..db6c9c5397 100644
--- a/Content.Server/Chemistry/Components/TransformableContainerComponent.cs
+++ b/Content.Server/Chemistry/Components/TransformableContainerComponent.cs
@@ -14,14 +14,6 @@ namespace Content.Server.Chemistry.Components;
[RegisterComponent, Access(typeof(TransformableContainerSystem))]
public sealed partial class TransformableContainerComponent : Component
{
- ///
- /// This is the initial metadata name for the container.
- /// It will revert to this when emptied.
- /// It defaults to the name of the parent entity unless overwritten.
- ///
- [DataField("initialName")]
- public string? InitialName;
-
///
/// This is the initial metadata description for the container.
/// It will revert to this when emptied.
diff --git a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs
index c375d97b8c..32bd912b22 100644
--- a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs
@@ -2,6 +2,7 @@ using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
+using Content.Shared.NameModifier.EntitySystems;
using Robust.Shared.Prototypes;
namespace Content.Server.Chemistry.EntitySystems;
@@ -11,6 +12,7 @@ public sealed class TransformableContainerSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
[Dependency] private readonly MetaDataSystem _metadataSystem = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
public override void Initialize()
{
@@ -18,15 +20,12 @@ public sealed class TransformableContainerSystem : EntitySystem
SubscribeLocalEvent(OnMapInit);
SubscribeLocalEvent(OnSolutionChange);
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
- private void OnMapInit(Entity entity, ref MapInitEvent args)
+ private void OnMapInit(Entity entity, ref MapInitEvent args)
{
var meta = MetaData(entity.Owner);
- if (string.IsNullOrEmpty(entity.Comp.InitialName))
- {
- entity.Comp.InitialName = meta.EntityName;
- }
if (string.IsNullOrEmpty(entity.Comp.InitialDescription))
{
entity.Comp.InitialDescription = meta.EntityDescription;
@@ -58,12 +57,20 @@ public sealed class TransformableContainerSystem : EntitySystem
&& _prototypeManager.TryIndex(reagentId.Value.Prototype, out ReagentPrototype? proto))
{
var metadata = MetaData(entity.Owner);
- var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName));
- _metadataSystem.SetEntityName(entity.Owner, val, metadata);
_metadataSystem.SetEntityDescription(entity.Owner, proto.LocalizedDescription, metadata);
entity.Comp.CurrentReagent = proto;
entity.Comp.Transformed = true;
}
+
+ _nameMod.RefreshNameModifiers(entity.Owner);
+ }
+
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
+ {
+ if (entity.Comp.CurrentReagent is { } currentReagent)
+ {
+ args.AddModifier("transformable-container-component-glass", priority: -1, ("reagent", currentReagent.LocalizedName));
+ }
}
private void CancelTransformation(Entity entity)
@@ -73,10 +80,8 @@ public sealed class TransformableContainerSystem : EntitySystem
var metadata = MetaData(entity);
- if (!string.IsNullOrEmpty(entity.Comp.InitialName))
- {
- _metadataSystem.SetEntityName(entity.Owner, entity.Comp.InitialName, metadata);
- }
+ _nameMod.RefreshNameModifiers(entity.Owner);
+
if (!string.IsNullOrEmpty(entity.Comp.InitialDescription))
{
_metadataSystem.SetEntityDescription(entity.Owner, entity.Comp.InitialDescription, metadata);
diff --git a/Content.Server/Cluwne/CluwneSystem.cs b/Content.Server/Cluwne/CluwneSystem.cs
index c170886a80..18d82659de 100644
--- a/Content.Server/Cluwne/CluwneSystem.cs
+++ b/Content.Server/Cluwne/CluwneSystem.cs
@@ -14,8 +14,8 @@ using Content.Server.Emoting.Systems;
using Content.Server.Speech.EntitySystems;
using Content.Shared.Cluwne;
using Content.Shared.Interaction.Components;
-using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
+using Content.Shared.NameModifier.EntitySystems;
namespace Content.Server.Cluwne;
@@ -30,6 +30,7 @@ public sealed class CluwneSystem : EntitySystem
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly AutoEmoteSystem _autoEmote = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
public override void Initialize()
{
@@ -39,6 +40,7 @@ public sealed class CluwneSystem : EntitySystem
SubscribeLocalEvent(OnMobState);
SubscribeLocalEvent(OnEmote, before:
new[] { typeof(VocalSystem), typeof(BodyEmotesSystem) });
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
///
@@ -47,19 +49,19 @@ public sealed class CluwneSystem : EntitySystem
private void OnMobState(EntityUid uid, CluwneComponent component, MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
- {
+ {
RemComp(uid);
RemComp(uid);
RemComp(uid);
var damageSpec = new DamageSpecifier(_prototypeManager.Index("Genetic"), 300);
_damageableSystem.TryChangeDamage(uid, damageSpec);
- }
+ }
}
public EmoteSoundsPrototype? EmoteSounds;
///
- /// OnStartup gives the cluwne outfit, ensures clumsy, gives name prefix and makes sure emote sounds are laugh.
+ /// OnStartup gives the cluwne outfit, ensures clumsy, and makes sure emote sounds are laugh.
///
private void OnComponentStartup(EntityUid uid, CluwneComponent component, ComponentStartup args)
{
@@ -67,9 +69,6 @@ public sealed class CluwneSystem : EntitySystem
return;
_prototypeManager.TryIndex(component.EmoteSoundsId, out EmoteSounds);
- var meta = MetaData(uid);
- var name = meta.EntityName;
-
EnsureComp(uid);
_autoEmote.AddEmote(uid, "CluwneGiggle");
EnsureComp(uid);
@@ -77,7 +76,7 @@ public sealed class CluwneSystem : EntitySystem
_popupSystem.PopupEntity(Loc.GetString("cluwne-transform", ("target", uid)), uid, PopupType.LargeCaution);
_audio.PlayPvs(component.SpawnSound, uid);
- _metaData.SetEntityName(uid, Loc.GetString("cluwne-name-prefix", ("target", name)), meta);
+ _nameMod.RefreshNameModifiers(uid);
SetOutfitCommand.SetOutfit(uid, "CluwneGear", EntityManager);
}
@@ -104,4 +103,12 @@ public sealed class CluwneSystem : EntitySystem
_chat.TrySendInGameICMessage(uid, "spasms", InGameICChatType.Emote, ChatTransmitRange.Normal);
}
}
+
+ ///
+ /// Applies "Cluwnified" prefix
+ ///
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
+ {
+ args.AddModifier("cluwne-name-prefix");
+ }
}
diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs
index 16d2d391f6..82acb3c60c 100644
--- a/Content.Server/Fax/FaxSystem.cs
+++ b/Content.Server/Fax/FaxSystem.cs
@@ -29,6 +29,7 @@ using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
+using Content.Shared.NameModifier.Components;
namespace Content.Server.Fax;
@@ -464,10 +465,11 @@ public sealed class FaxSystem : EntitySystem
return;
TryComp(sendEntity, out var labelComponent);
+ TryComp(sendEntity, out var nameMod);
// TODO: See comment in 'Send()' about not being able to copy whole entities
var printout = new FaxPrintout(paper.Content,
- labelComponent?.OriginalName ?? metadata.EntityName,
+ nameMod?.BaseName ?? metadata.EntityName,
labelComponent?.CurrentLabel,
metadata.EntityPrototype?.ID ?? DefaultPaperPrototypeId,
paper.StampState,
@@ -510,12 +512,14 @@ public sealed class FaxSystem : EntitySystem
!TryComp(sendEntity, out var paper))
return;
+ TryComp(sendEntity, out var nameMod);
+
TryComp(sendEntity, out var labelComponent);
var payload = new NetworkPayload()
{
{ DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand },
- { FaxConstants.FaxPaperNameData, labelComponent?.OriginalName ?? metadata.EntityName },
+ { FaxConstants.FaxPaperNameData, nameMod?.BaseName ?? metadata.EntityName },
{ FaxConstants.FaxPaperLabelData, labelComponent?.CurrentLabel },
{ FaxConstants.FaxPaperContentData, paper.Content },
};
diff --git a/Content.Server/Glue/GlueSystem.cs b/Content.Server/Glue/GlueSystem.cs
index ff53ef91ca..79249f5bd9 100644
--- a/Content.Server/Glue/GlueSystem.cs
+++ b/Content.Server/Glue/GlueSystem.cs
@@ -6,6 +6,7 @@ using Content.Shared.Hands;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Item;
+using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Verbs;
@@ -20,9 +21,9 @@ public sealed class GlueSystem : SharedGlueSystem
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly IGameTiming _timing = default!;
- [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly OpenableSystem _openable = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
public override void Initialize()
{
@@ -32,6 +33,7 @@ public sealed class GlueSystem : SharedGlueSystem
SubscribeLocalEvent(OnGluedInit);
SubscribeLocalEvent>(OnUtilityVerb);
SubscribeLocalEvent(OnHandPickUp);
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
// When glue bottle is used on item it will apply the glued and unremoveable components.
@@ -95,27 +97,22 @@ public sealed class GlueSystem : SharedGlueSystem
{
base.Update(frameTime);
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var uid, out var glue, out var _, out var meta))
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var glue, out var _))
{
if (_timing.CurTime < glue.Until)
continue;
- // Instead of string matching, just reconstruct the expected name and compare
- if (meta.EntityName == Loc.GetString("glued-name-prefix", ("target", glue.BeforeGluedEntityName)))
- _metaData.SetEntityName(uid, glue.BeforeGluedEntityName);
-
RemComp(uid);
RemComp(uid);
+
+ _nameMod.RefreshNameModifiers(uid);
}
}
private void OnGluedInit(Entity entity, ref ComponentInit args)
{
- var meta = MetaData(entity);
- var name = meta.EntityName;
- entity.Comp.BeforeGluedEntityName = meta.EntityName;
- _metaData.SetEntityName(entity.Owner, Loc.GetString("glued-name-prefix", ("target", name)));
+ _nameMod.RefreshNameModifiers(entity.Owner);
}
private void OnHandPickUp(Entity entity, ref GotEquippedHandEvent args)
@@ -124,4 +121,9 @@ public sealed class GlueSystem : SharedGlueSystem
comp.DeleteOnDrop = false;
entity.Comp.Until = _timing.CurTime + entity.Comp.Duration;
}
+
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
+ {
+ args.AddModifier("glued-name-prefix");
+ }
}
diff --git a/Content.Server/Labels/Label/LabelSystem.cs b/Content.Server/Labels/Label/LabelSystem.cs
index aee2abe7ab..17d18918fe 100644
--- a/Content.Server/Labels/Label/LabelSystem.cs
+++ b/Content.Server/Labels/Label/LabelSystem.cs
@@ -5,6 +5,7 @@ using Content.Shared.Examine;
using Content.Shared.Labels;
using Content.Shared.Labels.Components;
using Content.Shared.Labels.EntitySystems;
+using Content.Shared.NameModifier.EntitySystems;
using JetBrains.Annotations;
using Robust.Shared.Containers;
@@ -18,7 +19,7 @@ namespace Content.Server.Labels
{
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
- [Dependency] private readonly MetaDataSystem _metaData = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
public const string ContainerName = "paper_label";
@@ -41,6 +42,8 @@ namespace Content.Server.Labels
component.CurrentLabel = Loc.GetString(component.CurrentLabel);
Dirty(uid, component);
}
+
+ _nameMod.RefreshNameModifiers(uid);
}
///
@@ -52,30 +55,11 @@ namespace Content.Server.Labels
/// metadata component for resolve
public override void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null)
{
- if (!Resolve(uid, ref metadata))
- return;
if (!Resolve(uid, ref label, false))
label = EnsureComp(uid);
- if (string.IsNullOrEmpty(text))
- {
- if (label.OriginalName is null)
- return;
-
- // Remove label
- _metaData.SetEntityName(uid, label.OriginalName, metadata);
- label.CurrentLabel = null;
- label.OriginalName = null;
-
- Dirty(uid, label);
-
- return;
- }
-
- // Update label
- label.OriginalName ??= metadata.EntityName;
label.CurrentLabel = text;
- _metaData.SetEntityName(uid, $"{label.OriginalName} ({text})", metadata);
+ _nameMod.RefreshNameModifiers(uid);
Dirty(uid, label);
}
diff --git a/Content.Server/Lube/LubedSystem.cs b/Content.Server/Lube/LubedSystem.cs
index f786c5f91a..c2d15c8a28 100644
--- a/Content.Server/Lube/LubedSystem.cs
+++ b/Content.Server/Lube/LubedSystem.cs
@@ -1,5 +1,6 @@
using Content.Shared.IdentityManagement;
using Content.Shared.Lube;
+using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Throwing;
using Robust.Shared.Containers;
@@ -9,11 +10,11 @@ namespace Content.Server.Lube;
public sealed class LubedSystem : EntitySystem
{
- [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
public override void Initialize()
{
@@ -21,14 +22,12 @@ public sealed class LubedSystem : EntitySystem
SubscribeLocalEvent(OnInit);
SubscribeLocalEvent(OnHandPickUp);
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
private void OnInit(EntityUid uid, LubedComponent component, ComponentInit args)
{
- var meta = MetaData(uid);
- var name = meta.EntityName;
- component.BeforeLubedEntityName = meta.EntityName;
- _metaData.SetEntityName(uid, Loc.GetString("lubed-name-prefix", ("target", name)));
+ _nameMod.RefreshNameModifiers(uid);
}
private void OnHandPickUp(EntityUid uid, LubedComponent component, ContainerGettingInsertedAttemptEvent args)
@@ -36,7 +35,7 @@ public sealed class LubedSystem : EntitySystem
if (component.SlipsLeft <= 0)
{
RemComp(uid);
- _metaData.SetEntityName(uid, component.BeforeLubedEntityName);
+ _nameMod.RefreshNameModifiers(uid);
return;
}
component.SlipsLeft--;
@@ -47,4 +46,9 @@ public sealed class LubedSystem : EntitySystem
_throwing.TryThrow(uid, _random.NextVector2(), strength: component.SlipStrength);
_popup.PopupEntity(Loc.GetString("lube-slip", ("target", Identity.Entity(uid, EntityManager))), user, user, PopupType.MediumCaution);
}
+
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
+ {
+ args.AddModifier("lubed-name-prefix");
+ }
}
diff --git a/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs b/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs
index e224c7c479..e5f590a362 100644
--- a/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs
+++ b/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs
@@ -5,13 +5,12 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Interaction.Components;
using Content.Shared.Mind.Components;
using Content.Shared.Mobs.Systems;
+using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Nutrition.AnimalHusbandry;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Storage;
using Content.Shared.Whitelist;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Random;
@@ -29,12 +28,12 @@ public sealed class AnimalHusbandrySystem : EntitySystem
[Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
private readonly HashSet _failedAttempts = new();
private readonly HashSet _birthQueue = new();
@@ -43,8 +42,7 @@ public sealed class AnimalHusbandrySystem : EntitySystem
public override void Initialize()
{
SubscribeLocalEvent(OnMindAdded);
- SubscribeLocalEvent(OnInfantStartup);
- SubscribeLocalEvent(OnInfantShutdown);
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
// we express EZ-pass terminate the pregnancy if a player takes the role
@@ -54,16 +52,11 @@ public sealed class AnimalHusbandrySystem : EntitySystem
component.GestationEndTime = null;
}
- private void OnInfantStartup(EntityUid uid, InfantComponent component, ComponentStartup args)
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
{
- var meta = MetaData(uid);
- component.OriginalName = meta.EntityName;
- _metaData.SetEntityName(uid, Loc.GetString("infant-name-prefix", ("name", meta.EntityName)), meta);
- }
-
- private void OnInfantShutdown(EntityUid uid, InfantComponent component, ComponentShutdown args)
- {
- _metaData.SetEntityName(uid, component.OriginalName);
+ // This check may seem redundant, but it makes sure that the prefix is removed before the component is removed
+ if (_timing.CurTime < entity.Comp.InfantEndTime)
+ args.AddModifier("infant-name-prefix");
}
///
@@ -202,6 +195,8 @@ public sealed class AnimalHusbandrySystem : EntitySystem
{
var infant = AddComp(offspring);
infant.InfantEndTime = _timing.CurTime + infant.InfantDuration;
+ // Make sure the name prefix is applied
+ _nameMod.RefreshNameModifiers(offspring);
}
_adminLog.Add(LogType.Action, $"{ToPrettyString(uid)} gave birth to {ToPrettyString(offspring)}.");
}
@@ -249,6 +244,8 @@ public sealed class AnimalHusbandrySystem : EntitySystem
if (_timing.CurTime < infant.InfantEndTime)
continue;
RemCompDeferred(uid, infant);
+ // Make sure the name prefix gets removed
+ _nameMod.RefreshNameModifiers(uid);
}
}
}
diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs
index 0a745d5fc7..a8952009e6 100644
--- a/Content.Server/Zombies/ZombieSystem.Transform.cs
+++ b/Content.Server/Zombies/ZombieSystem.Transform.cs
@@ -222,9 +222,7 @@ namespace Content.Server.Zombies
_faction.AddFaction(target, "Zombie");
//gives it the funny "Zombie ___" name.
- var meta = MetaData(target);
- zombiecomp.BeforeZombifiedEntityName = meta.EntityName;
- _metaData.SetEntityName(target, Loc.GetString("zombie-name-prefix", ("target", meta.EntityName)), meta);
+ _nameMod.RefreshNameModifiers(target);
_identity.QueueIdentityUpdate(target);
diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs
index 552fd2781c..371c6f1222 100644
--- a/Content.Server/Zombies/ZombieSystem.cs
+++ b/Content.Server/Zombies/ZombieSystem.cs
@@ -14,6 +14,7 @@ using Content.Shared.Mind;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
+using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Zombies;
@@ -34,9 +35,9 @@ namespace Content.Server.Zombies
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly AutoEmoteSystem _autoEmote = default!;
[Dependency] private readonly EmoteOnDamageSystem _emoteOnDamage = default!;
- [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
public const SlotFlags ProtectiveSlots =
SlotFlags.FEET |
@@ -281,7 +282,7 @@ namespace Content.Server.Zombies
_humanoidAppearance.SetSkinColor(target, zombiecomp.BeforeZombifiedSkinColor, false);
_bloodstream.ChangeBloodReagent(target, zombiecomp.BeforeZombifiedBloodReagent);
- _metaData.SetEntityName(target, zombiecomp.BeforeZombifiedEntityName);
+ _nameMod.RefreshNameModifiers(target);
return true;
}
diff --git a/Content.Shared/Glue/GluedComponent.cs b/Content.Shared/Glue/GluedComponent.cs
index fd7a52fdb1..4b46f0aa5b 100644
--- a/Content.Shared/Glue/GluedComponent.cs
+++ b/Content.Shared/Glue/GluedComponent.cs
@@ -6,11 +6,6 @@ namespace Content.Shared.Glue;
[Access(typeof(SharedGlueSystem))]
public sealed partial class GluedComponent : Component
{
- ///
- /// Reverts name to before prefix event (essentially removes prefix).
- ///
- [DataField("beforeGluedEntityName"), ViewVariables(VVAccess.ReadOnly)]
- public string BeforeGluedEntityName = string.Empty;
[DataField("until", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Until;
diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs
index ea368884e0..bca9eb6cfa 100644
--- a/Content.Shared/Inventory/InventorySystem.Relay.cs
+++ b/Content.Shared/Inventory/InventorySystem.Relay.cs
@@ -7,6 +7,7 @@ using Content.Shared.Gravity;
using Content.Shared.IdentityManagement.Components;
using Content.Shared.Inventory.Events;
using Content.Shared.Movement.Systems;
+using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Overlays;
using Content.Shared.Radio;
using Content.Shared.Slippery;
@@ -28,6 +29,7 @@ public partial class InventorySystem
SubscribeLocalEvent(RelayInventoryEvent);
SubscribeLocalEvent(RelayInventoryEvent);
SubscribeLocalEvent(RelayInventoryEvent);
+ SubscribeLocalEvent(RelayInventoryEvent);
// by-ref events
SubscribeLocalEvent(RefRelayInventoryEvent);
diff --git a/Content.Shared/Labels/Components/LabelComponent.cs b/Content.Shared/Labels/Components/LabelComponent.cs
index c0dccd3481..d57023c8ab 100644
--- a/Content.Shared/Labels/Components/LabelComponent.cs
+++ b/Content.Shared/Labels/Components/LabelComponent.cs
@@ -14,11 +14,4 @@ public sealed partial class LabelComponent : Component
///
[DataField, AutoNetworkedField]
public string? CurrentLabel { get; set; }
-
- ///
- /// The original name of the entity
- /// Used for reverting the modified entity name when the label is removed
- ///
- [DataField, AutoNetworkedField]
- public string? OriginalName { get; set; }
}
diff --git a/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs b/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs
index 1189bb46d0..f1998e524d 100644
--- a/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs
+++ b/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs
@@ -1,5 +1,6 @@
using Content.Shared.Examine;
using Content.Shared.Labels.Components;
+using Content.Shared.NameModifier.EntitySystems;
using Robust.Shared.Utility;
namespace Content.Shared.Labels.EntitySystems;
@@ -11,6 +12,7 @@ public abstract partial class SharedLabelSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent(OnExamine);
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
public virtual void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null){}
@@ -27,4 +29,10 @@ public abstract partial class SharedLabelSystem : EntitySystem
message.AddText(Loc.GetString("hand-labeler-has-label", ("label", label.CurrentLabel)));
args.PushMessage(message);
}
+
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
+ {
+ if (!string.IsNullOrEmpty(entity.Comp.CurrentLabel))
+ args.AddModifier("comp-label-format", extraArgs: ("label", entity.Comp.CurrentLabel));
+ }
}
diff --git a/Content.Shared/Lube/LubedComponent.cs b/Content.Shared/Lube/LubedComponent.cs
index fe1946ddb1..9d032a077e 100644
--- a/Content.Shared/Lube/LubedComponent.cs
+++ b/Content.Shared/Lube/LubedComponent.cs
@@ -3,12 +3,6 @@ namespace Content.Shared.Lube;
[RegisterComponent]
public sealed partial class LubedComponent : Component
{
- ///
- /// Reverts name to before prefix event (essentially removes prefix).
- ///
- [DataField("beforeLubedEntityName")]
- public string BeforeLubedEntityName = string.Empty;
-
[DataField("slipsLeft"), ViewVariables(VVAccess.ReadWrite)]
public int SlipsLeft;
diff --git a/Content.Shared/NameModifier/Components/ModifyWearerNameComponent.cs b/Content.Shared/NameModifier/Components/ModifyWearerNameComponent.cs
new file mode 100644
index 0000000000..781ed3daae
--- /dev/null
+++ b/Content.Shared/NameModifier/Components/ModifyWearerNameComponent.cs
@@ -0,0 +1,25 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.NameModifier.Components;
+
+///
+/// Adds a modifier to the wearer's name when this item is equipped,
+/// and removes it when it is unequipped.
+///
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState]
+public sealed partial class ModifyWearerNameComponent : Component
+{
+ ///
+ /// The localization ID of the text to be used as the modifier.
+ /// The base name will be passed in as $baseName
+ ///
+ [DataField, AutoNetworkedField]
+ public LocId LocId = string.Empty;
+
+ ///
+ /// Priority of the modifier. See for more information.
+ ///
+ [DataField, AutoNetworkedField]
+ public int Priority;
+}
diff --git a/Content.Shared/NameModifier/Components/NameModifierComponent.cs b/Content.Shared/NameModifier/Components/NameModifierComponent.cs
new file mode 100644
index 0000000000..3a9dd9712b
--- /dev/null
+++ b/Content.Shared/NameModifier/Components/NameModifierComponent.cs
@@ -0,0 +1,20 @@
+using Content.Shared.NameModifier.EntitySystems;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.NameModifier.Components;
+
+///
+/// Used to manage modifiers on an entity's name and handle renaming in a way
+/// that survives being renamed by multiple systems.
+///
+[RegisterComponent]
+[NetworkedComponent, AutoGenerateComponentState]
+[Access(typeof(NameModifierSystem))]
+public sealed partial class NameModifierComponent : Component
+{
+ ///
+ /// The entity's name without any modifiers applied.
+ ///
+ [DataField, AutoNetworkedField]
+ public string BaseName = string.Empty;
+}
diff --git a/Content.Shared/NameModifier/EntitySystems/ModifyWearerNameSystem.cs b/Content.Shared/NameModifier/EntitySystems/ModifyWearerNameSystem.cs
new file mode 100644
index 0000000000..e728e6cdb5
--- /dev/null
+++ b/Content.Shared/NameModifier/EntitySystems/ModifyWearerNameSystem.cs
@@ -0,0 +1,34 @@
+using Content.Shared.Clothing;
+using Content.Shared.Inventory;
+using Content.Shared.NameModifier.Components;
+
+namespace Content.Shared.NameModifier.EntitySystems;
+
+public sealed partial class ModifyWearerNameSystem : EntitySystem
+{
+ [Dependency] private readonly NameModifierSystem _nameMod = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent>(OnRefreshNameModifiers);
+ SubscribeLocalEvent(OnGotEquipped);
+ SubscribeLocalEvent(OnGotUnequipped);
+ }
+
+ private void OnGotEquipped(Entity entity, ref ClothingGotEquippedEvent args)
+ {
+ _nameMod.RefreshNameModifiers(args.Wearer);
+ }
+
+ private void OnGotUnequipped(Entity entity, ref ClothingGotUnequippedEvent args)
+ {
+ _nameMod.RefreshNameModifiers(args.Wearer);
+ }
+
+ private void OnRefreshNameModifiers(Entity entity, ref InventoryRelayedEvent args)
+ {
+ args.Args.AddModifier(entity.Comp.LocId, entity.Comp.Priority);
+ }
+}
diff --git a/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs b/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs
new file mode 100644
index 0000000000..4dffb51805
--- /dev/null
+++ b/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs
@@ -0,0 +1,143 @@
+using System.Linq;
+using Content.Shared.Inventory;
+using Content.Shared.NameModifier.Components;
+
+namespace Content.Shared.NameModifier.EntitySystems;
+
+///
+public sealed partial class NameModifierSystem : EntitySystem
+{
+ [Dependency] private readonly MetaDataSystem _metaData = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnEntityRenamed);
+ }
+
+ private void OnEntityRenamed(Entity entity, ref EntityRenamedEvent args)
+ {
+ SetBaseName((entity, entity.Comp), args.NewName);
+ RefreshNameModifiers((entity, entity.Comp));
+ }
+
+ private void SetBaseName(Entity entity, string name)
+ {
+ if (name == entity.Comp.BaseName)
+ return;
+
+ // Set the base name to the new name
+ entity.Comp.BaseName = name;
+ Dirty(entity);
+ }
+
+ ///
+ /// Raises a to gather modifiers and
+ /// updates the entity's name to its base name with modifiers applied.
+ /// This will add a if any modifiers are added.
+ ///
+ ///
+ /// Call this to update the entity's name when adding or removing a modifier.
+ ///
+ public void RefreshNameModifiers(Entity entity)
+ {
+ var meta = MetaData(entity);
+ var baseName = meta.EntityName;
+ if (Resolve(entity, ref entity.Comp, logMissing: false))
+ baseName = entity.Comp.BaseName;
+
+ // Raise an event to get any modifiers
+ // If the entity already has the component, use its BaseName, otherwise use the entity's name from metadata
+ var modifierEvent = new RefreshNameModifiersEvent(baseName);
+ RaiseLocalEvent(entity, ref modifierEvent);
+
+ // Nothing added a modifier, so we can just use the base name
+ if (modifierEvent.ModifierCount == 0)
+ {
+ // If the entity doesn't have the component, we're done
+ if (entity.Comp == null)
+ return;
+
+ // Restore the base name
+ _metaData.SetEntityName(entity, entity.Comp.BaseName, meta, raiseEvents: false);
+ // The component isn't doing anything anymore, so remove it
+ RemComp(entity);
+ return;
+ }
+ // We have at least one modifier, so we need to apply it to the entity.
+
+ // Get the final name with modifiers applied
+ var modifiedName = modifierEvent.GetModifiedName();
+
+ // Add the component if needed, and initialize it with the base name
+ if (!EnsureComp(entity, out var comp))
+ SetBaseName((entity, comp), meta.EntityName);
+
+ // Set the entity's name with modifiers applied
+ _metaData.SetEntityName(entity, modifiedName, meta, raiseEvents: false);
+ }
+}
+
+///
+/// Raised on an entity when is called.
+/// Subscribe to this event and use its methods to add modifiers to the entity's name.
+///
+[ByRefEvent]
+public sealed class RefreshNameModifiersEvent : IInventoryRelayEvent
+{
+ ///
+ /// The entity's name without any modifiers applied.
+ /// If you want to base a modifier on the entity's name, use
+ /// this so you don't include other modifiers.
+ ///
+ public readonly string BaseName;
+
+ private readonly List<(LocId LocId, int Priority, (string, object)[] ExtraArgs)> _modifiers = [];
+
+ ///
+ public SlotFlags TargetSlots => ~SlotFlags.POCKET;
+
+ ///
+ /// How many modifiers have been added to this event.
+ ///
+ public int ModifierCount => _modifiers.Count;
+
+ public RefreshNameModifiersEvent(string baseName)
+ {
+ BaseName = baseName;
+ }
+
+ ///
+ /// Adds a modifier to the entity's name.
+ /// The original name will be passed to Fluent as $baseName along with any .
+ /// Modifiers with a higher will be applied later.
+ ///
+ public void AddModifier(LocId locId, int priority = 0, params (string, object)[] extraArgs)
+ {
+ _modifiers.Add((locId, priority, extraArgs));
+ }
+
+ ///
+ /// Returns the final name with all modifiers applied.
+ ///
+ public string GetModifiedName()
+ {
+ // Start out with the entity's name name
+ var name = BaseName;
+
+ // Iterate through all the modifiers in priority order
+ foreach (var modifier in _modifiers.OrderBy(n => n.Priority))
+ {
+ // Grab any extra args needed by the Loc string
+ var args = modifier.ExtraArgs;
+ // Add the current version of the entity name as an arg
+ Array.Resize(ref args, args.Length + 1);
+ args[^1] = ("baseName", name);
+ // Resolve the Loc string and use the result as the base in the next iteration.
+ name = Loc.GetString(modifier.LocId, args);
+ }
+
+ return name;
+ }
+}
diff --git a/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs b/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs
index 2708c823d2..06c533e646 100644
--- a/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs
+++ b/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs
@@ -35,10 +35,4 @@ public sealed partial class InfantComponent : Component
[DataField("infantEndTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan InfantEndTime;
-
- ///
- /// The entity's name before the "baby" prefix is added.
- ///
- [DataField("originalName")]
- public string OriginalName = string.Empty;
}
diff --git a/Content.Shared/Zombies/SharedZombieSystem.cs b/Content.Shared/Zombies/SharedZombieSystem.cs
index 6d9103639f..0388450a8c 100644
--- a/Content.Shared/Zombies/SharedZombieSystem.cs
+++ b/Content.Shared/Zombies/SharedZombieSystem.cs
@@ -1,4 +1,5 @@
using Content.Shared.Movement.Systems;
+using Content.Shared.NameModifier.EntitySystems;
namespace Content.Shared.Zombies;
@@ -10,6 +11,7 @@ public abstract class SharedZombieSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent(OnRefreshSpeed);
+ SubscribeLocalEvent(OnRefreshNameModifiers);
}
private void OnRefreshSpeed(EntityUid uid, ZombieComponent component, RefreshMovementSpeedModifiersEvent args)
@@ -17,4 +19,9 @@ public abstract class SharedZombieSystem : EntitySystem
var mod = component.ZombieMovementSpeedDebuff;
args.ModifySpeed(mod, mod);
}
+
+ private void OnRefreshNameModifiers(Entity entity, ref RefreshNameModifiersEvent args)
+ {
+ args.AddModifier("zombie-name-prefix");
+ }
}
diff --git a/Content.Shared/Zombies/ZombieComponent.cs b/Content.Shared/Zombies/ZombieComponent.cs
index 2cd0cdb96d..f510d65d6d 100644
--- a/Content.Shared/Zombies/ZombieComponent.cs
+++ b/Content.Shared/Zombies/ZombieComponent.cs
@@ -62,12 +62,6 @@ public sealed partial class ZombieComponent : Component
[DataField("zombieRoleId", customTypeSerializer: typeof(PrototypeIdSerializer))]
public string ZombieRoleId = "Zombie";
- ///
- /// The EntityName of the humanoid to restore in case of cloning
- ///
- [DataField("beforeZombifiedEntityName"), ViewVariables(VVAccess.ReadOnly)]
- public string BeforeZombifiedEntityName = string.Empty;
-
///
/// The CustomBaseLayers of the humanoid to restore in case of cloning
///
diff --git a/Resources/Locale/en-US/chemistry/components/transformable-container-component.ftl b/Resources/Locale/en-US/chemistry/components/transformable-container-component.ftl
index 21f096273d..ce43bd714a 100644
--- a/Resources/Locale/en-US/chemistry/components/transformable-container-component.ftl
+++ b/Resources/Locale/en-US/chemistry/components/transformable-container-component.ftl
@@ -1 +1 @@
-transformable-container-component-glass = {$name} glass
+transformable-container-component-glass = {$reagent} glass
diff --git a/Resources/Locale/en-US/cluwne/cluwne.ftl b/Resources/Locale/en-US/cluwne/cluwne.ftl
index 206df8657d..0ffd3f32df 100644
--- a/Resources/Locale/en-US/cluwne/cluwne.ftl
+++ b/Resources/Locale/en-US/cluwne/cluwne.ftl
@@ -1,2 +1,2 @@
cluwne-transform = {CAPITALIZE(THE($target))} turned into a cluwne!
-cluwne-name-prefix = Cluwnified {$target}
+cluwne-name-prefix = cluwnified {$baseName}
diff --git a/Resources/Locale/en-US/glue/glue.ftl b/Resources/Locale/en-US/glue/glue.ftl
index 1a711d51c2..158ebc9ed8 100644
--- a/Resources/Locale/en-US/glue/glue.ftl
+++ b/Resources/Locale/en-US/glue/glue.ftl
@@ -1,5 +1,5 @@
glue-success = {THE($target)} has been covered in glue!
-glued-name-prefix = Glued {$target}
+glued-name-prefix = glued {$baseName}
glue-failure = Can't cover {THE($target)} in glue!
glue-verb-text = Apply Glue
glue-verb-message = Glue an object
diff --git a/Resources/Locale/en-US/label/label-component.ftl b/Resources/Locale/en-US/label/label-component.ftl
new file mode 100644
index 0000000000..ff3a250c7b
--- /dev/null
+++ b/Resources/Locale/en-US/label/label-component.ftl
@@ -0,0 +1 @@
+comp-label-format = {$baseName} ({$label})
diff --git a/Resources/Locale/en-US/lube/lube.ftl b/Resources/Locale/en-US/lube/lube.ftl
index 92dd2802ec..1b5b66e069 100644
--- a/Resources/Locale/en-US/lube/lube.ftl
+++ b/Resources/Locale/en-US/lube/lube.ftl
@@ -1,5 +1,5 @@
lube-success = {THE($target)} has been covered in lube!
-lubed-name-prefix = Lubed {$target}
+lubed-name-prefix = lubed {$baseName}
lube-failure = Can't cover {THE($target)} in lube!
lube-slip = {THE($target)} slips out of your hands!
lube-verb-text = Apply Lube
diff --git a/Resources/Locale/en-US/nutrition/components/animal-husbandry.ftl b/Resources/Locale/en-US/nutrition/components/animal-husbandry.ftl
index 6ca108b653..cf7bf2d03a 100644
--- a/Resources/Locale/en-US/nutrition/components/animal-husbandry.ftl
+++ b/Resources/Locale/en-US/nutrition/components/animal-husbandry.ftl
@@ -1,3 +1,3 @@
-infant-name-prefix = baby {$name}
+infant-name-prefix = baby {$baseName}
reproductive-birth-popup = {CAPITALIZE(THE($parent))} gave birth!
reproductive-laid-egg-popup = {CAPITALIZE(THE($parent))} lays an egg!
diff --git a/Resources/Locale/en-US/zombies/zombie.ftl b/Resources/Locale/en-US/zombies/zombie.ftl
index a391a95b0d..d45943e825 100644
--- a/Resources/Locale/en-US/zombies/zombie.ftl
+++ b/Resources/Locale/en-US/zombies/zombie.ftl
@@ -2,7 +2,7 @@ zombie-transform = {CAPITALIZE(THE($target))} turned into a zombie!
zombie-infection-greeting = You have become a zombie. Your goal is to seek out the living and to try to infect them. Work together with the other zombies to overtake the station.
zombie-generic = zombie
-zombie-name-prefix = Zombified {$target}
+zombie-name-prefix = zombified {$baseName}
zombie-role-desc = A malevolent creature of the dead.
zombie-role-rules = You are an antagonist. Search out the living and bite them in order to infect them and turn them into zombies. Work together with the other zombies to overtake the station.
diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml
index 4bd71f898d..68d96fcd3d 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml
@@ -79,7 +79,6 @@
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Label
- originalName: jug
- type: Tag
tags:
- ChemDispensable