Skip to content

Commit

Permalink
Add option for character name colors in chat & move coloration to cli…
Browse files Browse the repository at this point in the history
…entside (space-wizards#24625)

* Adds option to disable character names in chat/speechbubbles

* Moved the coloring of names to clientside

* Move string functions to SharedChatSystem to avoid duplicate code in SpeechBubble.cs

* Changed to be put under Accessibility section

* Cache CVar
  • Loading branch information
SlamBamActionman authored Feb 11, 2024
1 parent fabcc2b commit 247be5b
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 49 deletions.
13 changes: 1 addition & 12 deletions Content.Client/Chat/UI/SpeechBubble.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,20 +182,9 @@ protected FormattedMessage FormatSpeech(string message, Color? fontColor = null)
return msg;
}

protected string ExtractSpeechSubstring(ChatMessage message, string tag)
{
var rawmsg = message.WrappedMessage;
var tagStart = rawmsg.IndexOf($"[{tag}]");
var tagEnd = rawmsg.IndexOf($"[/{tag}]");
if (tagStart < 0 || tagEnd < 0) //the above return -1 if the tag's not found, which in turn will cause the below to throw an exception. a blank speech bubble is far more noticeably broken than the bubble not appearing at all -bhijn
return "";
tagStart += tag.Length + 2;
return rawmsg.Substring(tagStart, tagEnd - tagStart);
}

protected FormattedMessage ExtractAndFormatSpeechSubstring(ChatMessage message, string tag, Color? fontColor = null)
{
return FormatSpeech(ExtractSpeechSubstring(message, tag), fontColor);
return FormatSpeech(SharedChatSystem.GetStringInsideTag(message, tag), fontColor);
}

}
Expand Down
1 change: 1 addition & 0 deletions Content.Client/Options/UI/Tabs/MiscTab.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
<Slider Name="ScreenShakeIntensitySlider"
Expand Down
5 changes: 5 additions & 0 deletions Content.Client/Options/UI/Tabs/MiscTab.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public MiscTab()
OpaqueStorageWindowCheckBox.OnToggled += OnCheckBoxToggled;
FancySpeechBubblesCheckBox.OnToggled += OnCheckBoxToggled;
FancyNameBackgroundsCheckBox.OnToggled += OnCheckBoxToggled;
EnableColorNameCheckBox.OnToggled += OnCheckBoxToggled;
ReducedMotionCheckBox.OnToggled += OnCheckBoxToggled;
ScreenShakeIntensitySlider.OnValueChanged += OnScreenShakeIntensitySliderChanged;
// ToggleWalk.OnToggled += OnCheckBoxToggled;
Expand All @@ -76,6 +77,7 @@ public MiscTab()
OpaqueStorageWindowCheckBox.Pressed = _cfg.GetCVar(CCVars.OpaqueStorageWindow);
FancySpeechBubblesCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
FancyNameBackgroundsCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatFancyNameBackground);
EnableColorNameCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableColorName);
ReducedMotionCheckBox.Pressed = _cfg.GetCVar(CCVars.ReducedMotion);
ScreenShakeIntensitySlider.Value = _cfg.GetCVar(CCVars.ScreenShakeIntensity) * 100f;
// ToggleWalk.Pressed = _cfg.GetCVar(CCVars.ToggleWalk);
Expand Down Expand Up @@ -120,6 +122,7 @@ private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
_cfg.SetCVar(CCVars.LoocAboveHeadShow, ShowLoocAboveHeadCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableColorName, EnableColorNameCheckBox.Pressed);
_cfg.SetCVar(CCVars.ReducedMotion, ReducedMotionCheckBox.Pressed);
_cfg.SetCVar(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider.Value / 100f);
// _cfg.SetCVar(CCVars.ToggleWalk, ToggleWalk.Pressed);
Expand All @@ -145,6 +148,7 @@ private void UpdateApplyButton()
var isLoocShowSame = ShowLoocAboveHeadCheckBox.Pressed == _cfg.GetCVar(CCVars.LoocAboveHeadShow);
var isFancyChatSame = FancySpeechBubblesCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
var isFancyBackgroundSame = FancyNameBackgroundsCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatFancyNameBackground);
var isEnableColorNameSame = EnableColorNameCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableColorName);
var isReducedMotionSame = ReducedMotionCheckBox.Pressed == _cfg.GetCVar(CCVars.ReducedMotion);
var isScreenShakeIntensitySame = Math.Abs(ScreenShakeIntensitySlider.Value / 100f - _cfg.GetCVar(CCVars.ScreenShakeIntensity)) < 0.01f;
// var isToggleWalkSame = ToggleWalk.Pressed == _cfg.GetCVar(CCVars.ToggleWalk);
Expand All @@ -159,6 +163,7 @@ private void UpdateApplyButton()
isLoocShowSame &&
isFancyChatSame &&
isFancyBackgroundSame &&
isEnableColorNameSame &&
isReducedMotionSame &&
isScreenShakeIntensitySame &&
// isToggleWalkSame &&
Expand Down
39 changes: 39 additions & 0 deletions Content.Client/UserInterface/Systems/Chat/ChatUIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Decals;
using Content.Shared.Damage.ForceSay;
using Content.Shared.Examine;
using Content.Shared.Input;
using Content.Shared.Radio;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
Expand All @@ -27,9 +29,11 @@
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects.Components.Localization;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Replays;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
Expand All @@ -42,9 +46,11 @@ public sealed class ChatUIController : UIController
[Dependency] private readonly IChatManager _manager = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IEntityManager _ent = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly IClientNetManager _net = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IReplayRecordingManager _replayRecording = default!;
Expand All @@ -55,6 +61,11 @@ public sealed class ChatUIController : UIController
[UISystemDependency] private readonly TypingIndicatorSystem? _typingIndicator = default;
[UISystemDependency] private readonly ChatSystem? _chatSys = default;

[ValidatePrototypeId<ColorPalettePrototype>]
private const string ChatNamePalette = "ChatNames";
private string[] _chatNameColors = default!;
private bool _chatNameColorsEnabled;

private ISawmill _sawmill = default!;

public static readonly Dictionary<char, ChatSelectChannel> PrefixToChannel = new()
Expand Down Expand Up @@ -168,6 +179,8 @@ public override void Initialize()
_net.RegisterNetMessage<MsgChatMessage>(OnChatMessage);
_net.RegisterNetMessage<MsgDeleteChatMessagesBy>(OnDeleteChatMessagesBy);
SubscribeNetworkEvent<DamageForceSayEvent>(OnDamageForceSay);
_cfg.OnValueChanged(CCVars.ChatEnableColorName, (value) => { _chatNameColorsEnabled = value; });
_chatNameColorsEnabled = _cfg.GetCVar(CCVars.ChatEnableColorName);

_speechBubbleRoot = new LayoutContainer();

Expand Down Expand Up @@ -212,6 +225,13 @@ public override void Initialize()
var gameplayStateLoad = UIManager.GetUIController<GameplayStateLoadController>();
gameplayStateLoad.OnScreenLoad += OnScreenLoad;
gameplayStateLoad.OnScreenUnload += OnScreenUnload;

var nameColors = _prototypeManager.Index<ColorPalettePrototype>(ChatNamePalette).Colors.Values.ToArray();
_chatNameColors = new string[nameColors.Length];
for (var i = 0; i < nameColors.Length; i++)
{
_chatNameColors[i] = nameColors[i].ToHex();
}
}

public void OnScreenLoad()
Expand Down Expand Up @@ -757,6 +777,14 @@ private void OnChatMessage(MsgChatMessage message)

public void ProcessChatMessage(ChatMessage msg, bool speechBubble = true)
{
// color the name unless it's something like "the old man"
if ((msg.Channel == ChatChannel.Local || msg.Channel == ChatChannel.Whisper) && _chatNameColorsEnabled)
{
var grammar = _ent.GetComponentOrNull<GrammarComponent>(_ent.GetEntity(msg.SenderEntity));
if (grammar != null && grammar.ProperNoun == true)
msg.WrappedMessage = SharedChatSystem.InjectTagInsideTag(msg, "Name", "color", GetNameColor(SharedChatSystem.GetStringInsideTag(msg, "Name")));
}

// Log all incoming chat to repopulate when filter is un-toggled
if (!msg.HideChat)
{
Expand Down Expand Up @@ -845,6 +873,17 @@ public void Repopulate()
}
}

/// <summary>
/// Returns the chat name color for a mob
/// </summary>
/// <param name="name">Name of the mob</param>
/// <returns>Hex value of the color</returns>
public string GetNameColor(string name)
{
var colorIdx = Math.Abs(name.GetHashCode() % _chatNameColors.Length);
return _chatNameColors[colorIdx];
}

private readonly record struct SpeechBubbleData(ChatMessage Message, SpeechBubble.SpeechType Type);

private sealed class SpeechBubbleQueueData
Expand Down
35 changes: 1 addition & 34 deletions Content.Server/Chat/Systems/ChatSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Decals;
using Content.Shared.Ghost;
using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement;
Expand All @@ -27,7 +26,6 @@
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects.Components.Localization;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
Expand Down Expand Up @@ -70,10 +68,6 @@ public sealed partial class ChatSystem : SharedChatSystem
private bool _critLoocEnabled;
private readonly bool _adminLoocEnabled = true;

[ValidatePrototypeId<ColorPalettePrototype>]
private const string ChatNamePalette = "ChatNames";
private string[] _chatNameColors = default!;

public override void Initialize()
{
base.Initialize();
Expand All @@ -83,13 +77,6 @@ public override void Initialize()
_configurationManager.OnValueChanged(CCVars.CritLoocEnabled, OnCritLoocEnabledChanged, true);

SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameChange);

var nameColors = _prototypeManager.Index<ColorPalettePrototype>(ChatNamePalette).Colors.Values.ToArray();
_chatNameColors = new string[nameColors.Length];
for (var i = 0; i < nameColors.Length; i++)
{
_chatNameColors[i] = nameColors[i].ToHex();
}
}

public override void Shutdown()
Expand Down Expand Up @@ -424,13 +411,8 @@ private void SendEntitySpeak(

name = FormattedMessage.EscapeText(name);

// color the name unless it's something like "the old man"
string coloredName = name;
if (!TryComp<GrammarComponent>(source, out var grammar) || grammar.ProperNoun == true)
coloredName = $"[color={GetNameColor(name)}]{name}[/color]";

var wrappedMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message",
("entityName", coloredName),
("entityName", name),
("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
("fontType", speech.FontId),
("fontSize", speech.FontSize),
Expand Down Expand Up @@ -499,10 +481,6 @@ private void SendEntityWhisper(
}
name = FormattedMessage.EscapeText(name);

// color the name unless it's something like "the old man"
if (!TryComp<GrammarComponent>(source, out var grammar) || grammar.ProperNoun == true)
name = $"[color={GetNameColor(name)}]{name}[/color]";

var wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message",
("entityName", name), ("message", FormattedMessage.EscapeText(message)));

Expand Down Expand Up @@ -643,17 +621,6 @@ private void SendDeadChat(EntityUid source, ICommonSession player, string messag

#region Utility

/// <summary>
/// Returns the chat name color for a mob
/// </summary>
/// <param name="name">Name of the mob</param>
/// <returns>Hex value of the color</returns>
public string GetNameColor(string name)
{
var colorIdx = Math.Abs(name.GetHashCode() % _chatNameColors.Length);
return _chatNameColors[colorIdx];
}

private enum MessageRangeCheckResult
{
Disallowed,
Expand Down
3 changes: 3 additions & 0 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,9 @@ public static readonly CVarDef<int>
public static readonly CVarDef<bool> ReducedMotion =
CVarDef.Create("accessibility.reduced_motion", false, CVar.CLIENTONLY | CVar.ARCHIVE);

public static readonly CVarDef<bool> ChatEnableColorName =
CVarDef.Create("accessibility.enable_color_name", true, CVar.CLIENTONLY | CVar.ARCHIVE, "Toggles displaying names with individual colors.");

/// <summary>
/// Screen shake intensity slider, controlling the intensity of the CameraRecoilSystem.
/// Goes from 0 (no recoil at all) to 1 (regular amounts of recoil)
Expand Down
27 changes: 27 additions & 0 deletions Content.Shared/Chat/SharedChatSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,31 @@ public static string SanitizeAnnouncement(string message, int maxLength = 0, int

return trimmed;
}

public static string InjectTagInsideTag(ChatMessage message, string outerTag, string innerTag, string? tagParameter)
{
var rawmsg = message.WrappedMessage;
var tagStart = rawmsg.IndexOf($"[{outerTag}]");
var tagEnd = rawmsg.IndexOf($"[/{outerTag}]");
if (tagStart < 0 || tagEnd < 0) //If the outer tag is not found, the injection is not performed
return rawmsg;
tagStart += outerTag.Length + 2;

string innerTagProcessed = tagParameter != null ? $"[{innerTag}={tagParameter}]" : $"[{innerTag}]";

rawmsg = rawmsg.Insert(tagEnd, $"[/{innerTag}]");
rawmsg = rawmsg.Insert(tagStart, innerTagProcessed);

return rawmsg;
}
public static string GetStringInsideTag(ChatMessage message, string tag)
{
var rawmsg = message.WrappedMessage;
var tagStart = rawmsg.IndexOf($"[{tag}]");
var tagEnd = rawmsg.IndexOf($"[/{tag}]");
if (tagStart < 0 || tagEnd < 0)
return "";
tagStart += tag.Length + 2;
return rawmsg.Substring(tagStart, tagEnd - tagStart);
}
}
6 changes: 3 additions & 3 deletions Resources/Locale/en-US/chat/managers/chat-manager.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ chat-manager-whisper-headset-on-message = You can't whisper on the radio!
chat-manager-server-wrap-message = [bold]{$message}[/bold]
chat-manager-sender-announcement-wrap-message = [font size=14][bold]{$sender} Announcement:[/font][font size=12]
{$message}[/bold][/font]
chat-manager-entity-say-wrap-message = [BubbleHeader][bold]{$entityName}[/bold][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent]{$message}[/BubbleContent]"[/font]
chat-manager-entity-say-bold-wrap-message = [BubbleHeader][bold]{$entityName}[/bold][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent][bold]{$message}[/bold][/BubbleContent]"[/font]
chat-manager-entity-say-wrap-message = [BubbleHeader][bold][Name]{$entityName}[/Name][/bold][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent]{$message}[/BubbleContent]"[/font]
chat-manager-entity-say-bold-wrap-message = [BubbleHeader][bold][Name]{$entityName}[/Name][/bold][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent][bold]{$message}[/bold][/BubbleContent]"[/font]
chat-manager-entity-whisper-wrap-message = [font size=11][italic][BubbleHeader]{$entityName}[/BubbleHeader] whispers,"[BubbleContent]{$message}[/BubbleContent]"[/italic][/font]
chat-manager-entity-whisper-wrap-message = [font size=11][italic][BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] whispers,"[BubbleContent]{$message}[/BubbleContent]"[/italic][/font]
chat-manager-entity-whisper-unknown-wrap-message = [font size=11][italic][BubbleHeader]Someone[/BubbleHeader] whispers, "[BubbleContent]{$message}[/BubbleContent]"[/italic][/font]
# THE() is not used here because the entity and its name can technically be disconnected if a nameOverride is passed...
Expand Down
1 change: 1 addition & 0 deletions Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ ui-options-opaque-storage-window = Opaque storage window
ui-options-show-looc-on-head = Show LOOC chat above characters head
ui-options-fancy-speech = Show names in speech bubbles
ui-options-fancy-name-background = Add background to speech bubble names
ui-options-enable-color-name = Add colors to character names
ui-options-reduced-motion = Reduce motion of visual effects
ui-options-screen-shake-intensity = Screen shake intensity
ui-options-screen-shake-percent = { TOSTRING($intensity, "P0") }
Expand Down

0 comments on commit 247be5b

Please sign in to comment.