diff --git a/Content.Client/Construction/ConstructionSystem.cs b/Content.Client/Construction/ConstructionSystem.cs index 1ec62280ea..e77a809a70 100644 --- a/Content.Client/Construction/ConstructionSystem.cs +++ b/Content.Client/Construction/ConstructionSystem.cs @@ -65,7 +65,7 @@ namespace Content.Client.Construction { if (component.Prototype == null) return; - args.Message.AddMarkup(Loc.GetString( + args.PushMarkup(Loc.GetString( "construction-ghost-examine-message", ("name", component.Prototype.Name))); diff --git a/Content.Server/Construction/ConstructionSystem.cs b/Content.Server/Construction/ConstructionSystem.cs index 65275a5cad..9da63b4765 100644 --- a/Content.Server/Construction/ConstructionSystem.cs +++ b/Content.Server/Construction/ConstructionSystem.cs @@ -58,10 +58,9 @@ namespace Content.Server.Construction { if (component.Target != null) { - args.Message.AddMarkup( - Loc.GetString( - "construction-component-to-create-header", - ("targetName", component.Target.Name)) + "\n"); + args.PushMarkup(Loc.GetString( + "construction-component-to-create-header", + ("targetName", component.Target.Name))); } if (component.Edge == null && component.TargetNextEdge != null) diff --git a/Content.Server/Dice/DiceSystem.cs b/Content.Server/Dice/DiceSystem.cs index 82d8438197..b9095bf878 100644 --- a/Content.Server/Dice/DiceSystem.cs +++ b/Content.Server/Dice/DiceSystem.cs @@ -59,10 +59,8 @@ namespace Content.Server.Dice private void OnExamined(EntityUid uid, DiceComponent dice, ExaminedEvent args) { //No details check, since the sprite updates to show the side. - args.Message.PushNewline(); - args.Message.AddMarkup(Loc.GetString("dice-component-on-examine-message-part-1", ("sidesAmount", dice.Sides))); - args.Message.PushNewline(); - args.Message.AddMarkup(Loc.GetString("dice-component-on-examine-message-part-2", ("currentSide", dice.CurrentSide))); + args.PushMarkup(Loc.GetString("dice-component-on-examine-message-part-1", ("sidesAmount", dice.Sides))); + args.PushMarkup(Loc.GetString("dice-component-on-examine-message-part-2", ("currentSide", dice.CurrentSide))); } } } diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index 4e1cc7ca38..0e7a731377 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -169,15 +169,13 @@ namespace Content.Server.Flash { if (!comp.HasUses) { - args.Message.AddText("\n"); - args.Message.AddText(Loc.GetString("flash-component-examine-empty")); + args.PushText(Loc.GetString("flash-component-examine-empty")); return; } if (args.IsInDetailsRange) { - args.Message.AddText("\n"); - args.Message.AddMarkup( + args.PushMarkup( Loc.GetString( "flash-component-examine-detail-count", ("count", comp.Uses), diff --git a/Content.Server/Fluids/PuddleSystem.cs b/Content.Server/Fluids/PuddleSystem.cs index e10569a533..48510fec2e 100644 --- a/Content.Server/Fluids/PuddleSystem.cs +++ b/Content.Server/Fluids/PuddleSystem.cs @@ -32,7 +32,7 @@ namespace Content.Server.Fluids { if (ComponentManager.TryGetComponent(uid, out var slippery) && slippery.Slippery) { - args.Message.AddText(Loc.GetString("puddle-component-examine-is-slipper-text")); + args.PushText(Loc.GetString("puddle-component-examine-is-slipper-text")); } } diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 8cdc54e471..5523ba9b78 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -86,7 +86,7 @@ namespace Content.Server.Ghost ? Loc.GetString("comp-ghost-examine-time-minutes", ("minutes", timeSinceDeath.Minutes)) : Loc.GetString("comp-ghost-examine-time-seconds", ("seconds", timeSinceDeath.Seconds)); - args.Message.AddMarkup(deathTimeInfo); + args.PushMarkup(deathTimeInfo); } private void OnMindRemovedMessage(EntityUid uid, GhostComponent component, MindRemovedMessage args) diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index 07fcd9712c..6461c65013 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -192,7 +192,7 @@ namespace Content.Server.Hands { foreach (var inhand in component.GetAllHeldItems()) { - args.Message.AddText($"\n{Loc.GetString("comp-hands-examine", ("user", component.Owner), ("item", inhand.Owner))}"); + args.PushText(Loc.GetString("comp-hands-examine", ("user", component.Owner), ("item", inhand.Owner))); } } diff --git a/Content.Server/Lock/LockSystem.cs b/Content.Server/Lock/LockSystem.cs index d8b6c65190..737cf2ac43 100644 --- a/Content.Server/Lock/LockSystem.cs +++ b/Content.Server/Lock/LockSystem.cs @@ -52,11 +52,10 @@ namespace Content.Server.Lock private void OnExamined(EntityUid eUI, LockComponent lockComp, ExaminedEvent args) { - args.Message.AddText("\n"); - args.Message.AddText(Loc.GetString(lockComp.Locked - ? "lock-comp-on-examined-is-locked" - : "lock-comp-on-examined-is-unlocked", - ("entityName", lockComp.Owner.Name))); + args.PushText(Loc.GetString(lockComp.Locked + ? "lock-comp-on-examined-is-locked" + : "lock-comp-on-examined-is-unlocked", + ("entityName", lockComp.Owner.Name))); } public void DoLock(LockComponent lockComp, ActivateInWorldEvent args) @@ -72,7 +71,7 @@ namespace Content.Server.Lock { SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.LockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5)); } - + if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearanceComp)) { appearanceComp.SetData(StorageVisuals.Locked, true); @@ -96,7 +95,7 @@ namespace Content.Server.Lock { SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.UnlockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5)); } - + if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearanceComp)) { appearanceComp.SetData(StorageVisuals.Locked, false); diff --git a/Content.Server/Stunnable/StunbatonSystem.cs b/Content.Server/Stunnable/StunbatonSystem.cs index 4bd2547d15..3efb8cdbb9 100644 --- a/Content.Server/Stunnable/StunbatonSystem.cs +++ b/Content.Server/Stunnable/StunbatonSystem.cs @@ -108,11 +108,10 @@ namespace Content.Server.Stunnable private void OnExamined(EntityUid uid, StunbatonComponent comp, ExaminedEvent args) { - args.Message.AddText("\n"); var msg = comp.Activated ? Loc.GetString("comp-stunbaton-examined-on") : Loc.GetString("comp-stunbaton-examined-off"); - args.Message.AddMarkup(msg); + args.PushMarkup(msg); } private void StunEntity(IEntity entity, StunbatonComponent comp) diff --git a/Content.Server/Tools/WelderSystem.cs b/Content.Server/Tools/WelderSystem.cs index 976763b626..bf3fb9a604 100644 --- a/Content.Server/Tools/WelderSystem.cs +++ b/Content.Server/Tools/WelderSystem.cs @@ -28,16 +28,16 @@ namespace Content.Server.Tools { if (component.WelderLit) { - args.Message.AddMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message") + "\n"); + args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message")); } else { - args.Message.AddText(Loc.GetString("welder-component-on-examine-welder-not-lit-message") + "\n"); + args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-not-lit-message")); } if (args.IsInDetailsRange) { - args.Message.AddMarkup(Loc.GetString("welder-component-on-examine-detailed-message", + args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message", ("colorName", component.Fuel < component.FuelCapacity / 4f ? "darkorange" : "orange"), ("fuelLeft", Math.Round(component.Fuel)), ("fuelCapacity", component.FuelCapacity))); diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs index 3ddc503be8..6f51044f1e 100644 --- a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs @@ -69,7 +69,7 @@ namespace Content.Shared.Chemistry.EntitySystems if (solutionHolder.Contents.Count == 0) { - args.Message.AddText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); + args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); return; } @@ -86,7 +86,7 @@ namespace Content.Shared.Chemistry.EntitySystems .ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable. var messageString = "shared-solution-container-component-on-examine-main-text"; - args.Message.AddMarkup(Loc.GetString(messageString, + args.PushMarkup(Loc.GetString(messageString, ("color", colorHex), ("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1 ? "shared-solution-container-component-on-examine-worded-amount-one-reagent" diff --git a/Content.Shared/Examine/ExamineSystemShared.cs b/Content.Shared/Examine/ExamineSystemShared.cs index 1785fbc795..4f3e4a915d 100644 --- a/Content.Shared/Examine/ExamineSystemShared.cs +++ b/Content.Shared/Examine/ExamineSystemShared.cs @@ -189,13 +189,15 @@ namespace Content.Shared.Examine message.PushColor(Color.DarkGray); // Raise the event and let things that subscribe to it change the message... - RaiseLocalEvent(entity.Uid, new ExaminedEvent(message, entity, examiner, IsInDetailsRange(examiner, entity))); + var isInDetailsRange = IsInDetailsRange(examiner, entity); + var examinedEvent = new ExaminedEvent(message, entity, examiner, isInDetailsRange, doNewline); + RaiseLocalEvent(entity.Uid, examinedEvent); //Add component statuses from components that report one foreach (var examineComponent in entity.GetAllComponents()) { var subMessage = new FormattedMessage(); - examineComponent.Examine(subMessage, IsInDetailsRange(examiner, entity)); + examineComponent.Examine(subMessage, isInDetailsRange); if (subMessage.Tags.Count == 0) continue; @@ -214,15 +216,17 @@ namespace Content.Shared.Examine /// /// Raised when an entity is examined. - /// You have to manually add a newline at the start, and perform cleanup (popping state) at the end. /// public class ExaminedEvent : EntityEventArgs { /// /// The message that will be displayed as the examine text. - /// Use the methods it exposes to change it, and don't forget to add a newline at the start! - /// Input/Output parameter. + /// For most use cases, you probably want to use and similar instead to modify this, + /// since it handles newlines and such correctly. /// + /// + /// + /// public FormattedMessage Message { get; } /// @@ -240,12 +244,54 @@ namespace Content.Shared.Examine /// public bool IsInDetailsRange { get; } - public ExaminedEvent(FormattedMessage message, IEntity examined, IEntity examiner, bool isInDetailsRange) + private bool _doNewLine; + + public ExaminedEvent(FormattedMessage message, IEntity examined, IEntity examiner, bool isInDetailsRange, bool doNewLine) { Message = message; Examined = examined; Examiner = examiner; IsInDetailsRange = isInDetailsRange; + _doNewLine = doNewLine; + } + + /// + /// Push another message into this examine result, on its own line. + /// + /// + /// + public void PushMessage(FormattedMessage message) + { + if (message.Tags.Count == 0) + return; + + if (_doNewLine) + Message.AddText("\n"); + + Message.AddMessage(message); + _doNewLine = true; + } + + /// + /// Push another message parsed from markup into this examine result, on its own line. + /// + /// + /// + public void PushMarkup(string markup) + { + PushMessage(FormattedMessage.FromMarkup(markup)); + } + + /// + /// Push another message containing raw text into this examine result, on its own line. + /// + /// + /// + public void PushText(string text) + { + var msg = new FormattedMessage(); + msg.AddText(text); + PushMessage(msg); } } } diff --git a/Content.Shared/Stacks/SharedStackSystem.cs b/Content.Shared/Stacks/SharedStackSystem.cs index b6c85dae77..5b33ec8fa2 100644 --- a/Content.Shared/Stacks/SharedStackSystem.cs +++ b/Content.Shared/Stacks/SharedStackSystem.cs @@ -100,8 +100,7 @@ namespace Content.Shared.Stacks if (!args.IsInDetailsRange) return; - args.Message.AddText("\n"); - args.Message.AddMarkup( + args.PushMarkup( Loc.GetString("comp-stack-examine-detail-count", ("count", component.Count), ("markupCountColor", "lightgray")