From 1ba7cd4944022ea0f00d60a6c36d569406fcb546 Mon Sep 17 00:00:00 2001 From: RadsammyT Date: Sun, 8 Feb 2026 23:52:06 -0500 Subject: [PATCH 1/2] Initial port of PinkText --- .../Character/CharacterUIController.cs | 17 +++++- .../CustomObjectiveSummaryUIController.cs | 48 ++++++++++++++++ .../CustomObjectiveSummaryWindow.xaml | 13 +++++ .../CustomObjectiveSummaryWindow.xaml.cs | 53 ++++++++++++++++++ Content.Server/Objectives/ObjectivesSystem.cs | 30 ++++++++++ .../Systems/EmergencyShuttleSystem.cs | 2 + .../CustomObjectiveSummarySystem.cs | 56 +++++++++++++++++++ Content.Shared.Database/LogType.cs | 1 + .../CustomObjectiveSummaryComponent.cs | 20 +++++++ .../CustomObjectiveSummeryEvents.cs | 46 +++++++++++++++ .../customobjectivesummary.ftl | 13 +++++ 11 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryUIController.cs create mode 100644 Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml create mode 100644 Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml.cs create mode 100644 Content.Server/_DV/CustomObjectiveSummary/CustomObjectiveSummarySystem.cs create mode 100644 Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummaryComponent.cs create mode 100644 Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummeryEvents.cs create mode 100644 Resources/Locale/en-US/_DV/customobjectivesummary/customobjectivesummary.ftl diff --git a/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs b/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs index 425dada2441..4d1b58fe3b6 100644 --- a/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs +++ b/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs @@ -25,6 +25,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later using System.Linq; +using Content.Client._DV.CustomObjectiveSummary; using Content.Client.CharacterInfo; using Content.Client.Gameplay; using Content.Client.Stylesheets; @@ -56,6 +57,7 @@ public sealed class CharacterUIController : UIController, IOnStateEntered 0) + { + var button = new Button + { + Text = Loc.GetString("custom-objective-button-text"), + Margin = new Thickness(0, 10, 0, 10) + }; + button.OnPressed += _ => _objective.OpenWindow(); + + _window.Objectives.AddChild(button); + } + // End DeltaV Additions if (briefing != null) { @@ -281,4 +296,4 @@ private void ToggleWindow() _window.Open(); } } -} \ No newline at end of file +} diff --git a/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryUIController.cs b/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryUIController.cs new file mode 100644 index 00000000000..a9cf6f536fe --- /dev/null +++ b/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryUIController.cs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025 beck-thompson <107373427+beck-thompson@users.noreply.github.com> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Content.Shared._DV.CustomObjectiveSummary; +using Robust.Client.UserInterface.Controllers; +using Robust.Shared.Network; + +namespace Content.Client._DV.CustomObjectiveSummary; + +public sealed class CustomObjectiveSummaryUIController : UIController +{ + [Dependency] private readonly IClientNetManager _net = default!; + + private CustomObjectiveSummaryWindow? _window; + + public override void Initialize() + { + base.Initialize(); + SubscribeNetworkEvent(OnCustomObjectiveSummaryOpen); + } + + private void OnCustomObjectiveSummaryOpen(CustomObjectiveSummaryOpenMessage msg, EntitySessionEventArgs args) + { + OpenWindow(); + } + + public void OpenWindow() + { + // If a window is already open, close it + _window?.Close(); + + _window = new CustomObjectiveSummaryWindow(); + _window.OpenCentered(); + _window.OnClose += () => _window = null; + _window.OnSubmitted += OnFeedbackSubmitted; + } + + private void OnFeedbackSubmitted(string args) + { + var msg = new CustomObjectiveClientSetObjective + { + Summary = args, + }; + _net.ClientSendMessage(msg); + _window?.Close(); + } +} diff --git a/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml b/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml new file mode 100644 index 00000000000..1e28d96a020 --- /dev/null +++ b/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml @@ -0,0 +1,13 @@ + + + + diff --git a/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml.cs b/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml.cs new file mode 100644 index 00000000000..f2fb6f6f3bc --- /dev/null +++ b/Content.Client/_DV/CustomObjectiveSummary/CustomObjectiveSummaryWindow.xaml.cs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025 beck-thompson <107373427+beck-thompson@users.noreply.github.com> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Content.Client.UserInterface.Controls; +using Content.Shared.Mind; +using Robust.Client.AutoGenerated; +using Robust.Client.Player; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Utility; + +namespace Content.Client._DV.CustomObjectiveSummary; + +[GenerateTypedNameReferences] +public sealed partial class CustomObjectiveSummaryWindow : FancyWindow +{ + [Dependency] private readonly IPlayerManager _players = default!; + [Dependency] private readonly IEntityManager _entity = default!; + + private SharedMindSystem? _mind; + + private readonly int _maxLength = 1024; + + public event Action? OnSubmitted; + + public CustomObjectiveSummaryWindow() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + SubmitButton.OnPressed += + _ => OnSubmitted?.Invoke(Rope.Collapse(ObjectiveSummaryTextEdit.TextRope)); + ObjectiveSummaryTextEdit.OnTextChanged += _ => UpdateWordCount(); + + _mind ??= _entity.System(); + + _mind.TryGetMind(_players.LocalSession, out var mindUid, out _); + + UpdateWordCount(); + + if (_entity.TryGetComponent(mindUid, out var summary)) + ObjectiveSummaryTextEdit.TextRope = new Rope.Leaf(summary.ObjectiveSummary); + + UpdateWordCount(); + } + + private void UpdateWordCount() + { + // Disable the button if its over the max length.sa + SubmitButton.Disabled = ObjectiveSummaryTextEdit.TextLength > _maxLength; + CharacterLimitLabel.Text = ObjectiveSummaryTextEdit.TextLength + "/" + _maxLength; + } +} diff --git a/Content.Server/Objectives/ObjectivesSystem.cs b/Content.Server/Objectives/ObjectivesSystem.cs index 101ab98d3db..bb05e8315c9 100644 --- a/Content.Server/Objectives/ObjectivesSystem.cs +++ b/Content.Server/Objectives/ObjectivesSystem.cs @@ -47,6 +47,7 @@ using Content.Goobstation.Common.ServerCurrency; using Content.Goobstation.Shared.ManifestListings; using Content.Server.Objectives.Commands; +using Content.Shared._DV.CustomObjectiveSummary; using Content.Shared.CCVar; using Content.Shared.Prototypes; using Content.Shared.Roles.Jobs; @@ -242,6 +243,7 @@ private void AddSummary(StringBuilder result, string agent, List<(EntityUid, str $"{username:subject} achieved {progress}% of objective {objectiveTitle}"); agentSummary.Append("- "); + /* DeltaV removal - Removed Greentext if (!_showGreentext) { agentSummary.AppendLine(objectiveTitle); @@ -292,10 +294,38 @@ private void AddSummary(StringBuilder result, string agent, List<(EntityUid, str ("progress", progress) )); } + */ + // Begin DeltaV Additions - Generic objective + agentSummary.AppendLine(Loc.GetString( + "objectives-objective", + ("objective", objectiveTitle) + )); } } var successRate = totalObjectives > 0 ? (float)completedObjectives / totalObjectives : 0f; + // Begin DeltaV Additions - custom objective response. + if (TryComp(mindId, out var customComp)) + { + // We have to spit it like this to make it readable. Yeah, it sucks but for some reason the entire thing + // is just one long string... + var words = customComp.ObjectiveSummary.Split(" "); + var currentLine = ""; + foreach (var word in words) + { + currentLine += word + " "; + + // magic number + if (currentLine.Length <= 50) + continue; + + agentSummary.AppendLine(Loc.GetString("custom-objective-format", ("line", currentLine))); + currentLine = ""; + } + + agentSummary.AppendLine(Loc.GetString("custom-objective-format", ("line", currentLine))); + } + // End DeltaV Additions agentSummaries.Add((agentSummary.ToString(), successRate, completedObjectives)); } diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index c79121b067c..cc3418ce283 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -83,6 +83,7 @@ using Content.Server.Station.Components; using Content.Server.Station.Events; using Content.Server.Station.Systems; +using Content.Shared._DV.CustomObjectiveSummary; // DeltaV using Content.Shared.Access.Systems; using Content.Shared.CCVar; using Content.Shared.Database; @@ -288,6 +289,7 @@ private void OnEmergencyFTL(EntityUid uid, EmergencyShuttleComponent component, }; _deviceNetworkSystem.QueuePacket(uid, null, payload, netComp.TransmitFrequency); } + RaiseLocalEvent(new EvacShuttleLeftEvent()); // DeltaV } /// diff --git a/Content.Server/_DV/CustomObjectiveSummary/CustomObjectiveSummarySystem.cs b/Content.Server/_DV/CustomObjectiveSummary/CustomObjectiveSummarySystem.cs new file mode 100644 index 00000000000..2982e9bf022 --- /dev/null +++ b/Content.Server/_DV/CustomObjectiveSummary/CustomObjectiveSummarySystem.cs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025 beck-thompson <107373427+beck-thompson@users.noreply.github.com> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Content.Server.Administration.Logs; +using Content.Shared._DV.CustomObjectiveSummary; +using Content.Shared.Database; +using Content.Shared.Mind; +using Robust.Shared.Network; + +namespace Content.Server._DV.CustomObjectiveSummary; + +public sealed class CustomObjectiveSummarySystem : EntitySystem +{ + [Dependency] private readonly IServerNetManager _net = default!; + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly IAdminLogManager _adminLog = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnEvacShuttleLeft); + + _net.RegisterNetMessage(OnCustomObjectiveFeedback); + } + + private void OnCustomObjectiveFeedback(CustomObjectiveClientSetObjective msg) + { + if (!_mind.TryGetMind(msg.MsgChannel.UserId, out var mind)) + return; + + if (mind.Value.Comp.Objectives.Count == 0) + return; + + var comp = EnsureComp(mind.Value); + + comp.ObjectiveSummary = msg.Summary; + Dirty(mind.Value.Owner, comp); + + _adminLog.Add(LogType.ObjectiveSummary, $"{ToPrettyString(mind.Value.Comp.OwnedEntity)} wrote objective summery: {msg.Summary}"); + } + + private void OnEvacShuttleLeft(EvacShuttleLeftEvent args) + { + var allMinds = _mind.GetAliveHumans(); + + // Assumes the assistant is still there at the end of the round. + foreach (var mind in allMinds) + { + // Only send the popup to people with objectives. + if (mind.Comp.Objectives.Count == 0) + continue; + + RaiseNetworkEvent(new CustomObjectiveSummaryOpenMessage(), mind.Owner); + } + } +} diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs index 2f52b17ea55..942e987c152 100644 --- a/Content.Shared.Database/LogType.cs +++ b/Content.Shared.Database/LogType.cs @@ -510,6 +510,7 @@ public enum LogType /// Tiles related interactions. /// Tile = 86, + ObjectiveSummary = 422, // DeltaV /// /// A client has sent too many chat messages recently and is temporarily blocked from sending more. diff --git a/Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummaryComponent.cs b/Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummaryComponent.cs new file mode 100644 index 00000000000..6262e5634d5 --- /dev/null +++ b/Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummaryComponent.cs @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2025 beck-thompson <107373427+beck-thompson@users.noreply.github.com> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Robust.Shared.GameStates; + +namespace Content.Shared._DV.CustomObjectiveSummary; + +/// +/// Put on a players mind if the wrote a custom summary for their objectives. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class CustomObjectiveSummaryComponent : Component +{ + /// + /// What the player wrote as their summary! + /// + [DataField, AutoNetworkedField] + public string ObjectiveSummary = ""; +} diff --git a/Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummeryEvents.cs b/Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummeryEvents.cs new file mode 100644 index 00000000000..70c1bec6bd7 --- /dev/null +++ b/Content.Shared/_DV/CustomObjectiveSummary/CustomObjectiveSummeryEvents.cs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025 beck-thompson <107373427+beck-thompson@users.noreply.github.com> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Lidgren.Network; +using Robust.Shared.Network; +using Robust.Shared.Serialization; + +namespace Content.Shared._DV.CustomObjectiveSummary; + +/// +/// Message from the client with what they are updating their summary to. +/// +public sealed class CustomObjectiveClientSetObjective : NetMessage +{ + public override MsgGroups MsgGroup => MsgGroups.EntityEvent; + + /// + /// The summary that the user wrote. + /// + public string Summary = string.Empty; + + public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) + { + Summary = buffer.ReadString(); + } + + public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) + { + buffer.Write(Summary); + } + + public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered; +} + +/// +/// Clients listen for this event and when they get it, they open a popup so the player can fill out the objective summary. +/// +[Serializable, NetSerializable] +public sealed class CustomObjectiveSummaryOpenMessage : EntityEventArgs; + +/// +/// DeltaV event for when the evac shuttle leaves. +/// +[Serializable, NetSerializable] +public sealed class EvacShuttleLeftEvent : EventArgs; diff --git a/Resources/Locale/en-US/_DV/customobjectivesummary/customobjectivesummary.ftl b/Resources/Locale/en-US/_DV/customobjectivesummary/customobjectivesummary.ftl new file mode 100644 index 00000000000..9102145ae7e --- /dev/null +++ b/Resources/Locale/en-US/_DV/customobjectivesummary/customobjectivesummary.ftl @@ -0,0 +1,13 @@ +custom-objective-button-text = Write objective summary + +# UI +custom-objective-window-title = Custom objective summary +custom-objective-window-submit-button-text = Submit +custom-objective-window-submit-button-text-confirm = Confirm submission +custom-objective-window-explain = Explain how you completed your objectives here! +custom-objective-window-explain-edit = You can always edit this anytime before the round ends. + +objectives-objective = {$objective} + +# End of round +custom-objective-format = [color=#FFAEC9] {$line}[/color] From c8315ace3becc5a51a1ccd6b6edb6251f268ff5d Mon Sep 17 00:00:00 2001 From: RadsammyT Date: Mon, 9 Feb 2026 00:21:11 -0500 Subject: [PATCH 2/2] fuck it. why not both? --- Content.Server/Objectives/ObjectivesSystem.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Content.Server/Objectives/ObjectivesSystem.cs b/Content.Server/Objectives/ObjectivesSystem.cs index bb05e8315c9..c2ba5ede40b 100644 --- a/Content.Server/Objectives/ObjectivesSystem.cs +++ b/Content.Server/Objectives/ObjectivesSystem.cs @@ -243,7 +243,8 @@ private void AddSummary(StringBuilder result, string agent, List<(EntityUid, str $"{username:subject} achieved {progress}% of objective {objectiveTitle}"); agentSummary.Append("- "); - /* DeltaV removal - Removed Greentext + // Omu: if you're going back to good ol' pinktext after green+pinktext drops, + // start a multiline comment starting here. if (!_showGreentext) { agentSummary.AppendLine(objectiveTitle); @@ -294,12 +295,14 @@ private void AddSummary(StringBuilder result, string agent, List<(EntityUid, str ("progress", progress) )); } - */ + // Omu: future multiline comment ends here // Begin DeltaV Additions - Generic objective + /* Omu: Green+PinkText agentSummary.AppendLine(Loc.GetString( "objectives-objective", ("objective", objectiveTitle) )); + */ } }