Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add codeword highlighting #30092

Merged
merged 8 commits into from
Aug 23, 2024
23 changes: 23 additions & 0 deletions Content.Client/Roles/RoleCodewordComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Content.Client.Roles;

/// <summary>
///
/// </summary>
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
[RegisterComponent]
public sealed partial class RoleCodewordComponent : Component
{
[DataField]
public Dictionary<string, CodewordsData> RoleCodewords = new();
}
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved

public struct CodewordsData
{
public Color Color;
public List<string> Codewords;

public CodewordsData(Color color, List<string> codewords)
{
Color = color;
Codewords = codewords;
}
}
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
20 changes: 20 additions & 0 deletions Content.Client/Roles/RoleCodewordSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Content.Shared.Roles;

namespace Content.Client.Roles;
public sealed class RoleCodewordSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();

SubscribeNetworkEvent<RoleCodewordEvent>(SetRoleCodewords);
}

private void SetRoleCodewords(RoleCodewordEvent args)
{
EntityUid mindId = GetEntity(args.Entity);

var comp = EnsureComp<RoleCodewordComponent>(mindId);
comp.RoleCodewords[args.RoleKey] = new CodewordsData(args.Color, args.Codewords);
}
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
}
16 changes: 16 additions & 0 deletions Content.Client/UserInterface/Systems/Chat/ChatUIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Content.Client.Examine;
using Content.Client.Gameplay;
using Content.Client.Ghost;
using Content.Client.Mind;
using Content.Client.Roles;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Screens;
using Content.Client.UserInterface.Systems.Chat.Widgets;
Expand Down Expand Up @@ -60,6 +62,7 @@ public sealed class ChatUIController : UIController
[UISystemDependency] private readonly TypingIndicatorSystem? _typingIndicator = default;
[UISystemDependency] private readonly ChatSystem? _chatSys = default;
[UISystemDependency] private readonly TransformSystem? _transform = default;
[UISystemDependency] private readonly MindSystem? _mindSystem = default!;

[ValidatePrototypeId<ColorPalettePrototype>]
private const string ChatNamePalette = "ChatNames";
Expand Down Expand Up @@ -819,6 +822,19 @@ public void ProcessChatMessage(ChatMessage msg, bool speechBubble = true)
msg.WrappedMessage = SharedChatSystem.InjectTagInsideTag(msg, "Name", "color", GetNameColor(SharedChatSystem.GetStringInsideTag(msg, "Name")));
}

// Color any codewords for minds that have roles that use them
if (_player.LocalUser != null && _mindSystem != null)
{
if (_mindSystem.TryGetMind(_player.LocalUser.Value, out var mindId) && _ent.TryGetComponent(mindId, out RoleCodewordComponent? codewordComp))
{
foreach (var (_, codewordData) in codewordComp.RoleCodewords)
{
foreach (string codeword in codewordData.Codewords)
msg.WrappedMessage = SharedChatSystem.InjectTagAroundString(msg, codeword, "color", codewordData.Color.ToHex());
}
}
}

// Log all incoming chat to repopulate when filter is un-toggled
if (!msg.HideChat)
{
Expand Down
12 changes: 12 additions & 0 deletions Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Content.Shared.NPC.Systems;
using Content.Shared.Objectives.Components;
using Content.Shared.PDA;
using Content.Shared.Radio;
using Content.Shared.Roles;
using Content.Shared.Roles.Jobs;
using Robust.Shared.Prototypes;
Expand All @@ -21,6 +22,9 @@ namespace Content.Server.GameTicking.Rules;

public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
{
private static readonly Color TraitorFallbackColor = Color.FromHex("#8f4a4b");
private static readonly string TraitorRadioChannel = "Syndicate";

[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
Expand Down Expand Up @@ -97,6 +101,14 @@ public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool

_antag.SendBriefing(traitor, GenerateBriefing(component.Codewords, code, issuer), null, component.GreetSoundNotification);

// Send codewords to only the traitor client
var color = TraitorFallbackColor; // Fall back to a dark red Syndicate color if a prototype is not found
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
if (_prototypeManager.TryIndex(TraitorRadioChannel, out RadioChannelPrototype? syndieChannel))
{
color = syndieChannel.Color;
}
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
RaiseNetworkEvent(new RoleCodewordEvent(GetNetEntity(mindId), color, "traitor", component.Codewords.ToList()), traitor);
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved

component.TraitorMinds.Add(mindId);

// Assign briefing
Expand Down
12 changes: 12 additions & 0 deletions Content.Shared/Chat/SharedChatSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Frozen;
using System.Text.RegularExpressions;
using Content.Shared.Popups;
using Content.Shared.Radio;
using Content.Shared.Speech;
Expand Down Expand Up @@ -237,6 +238,17 @@ public static string InjectTagInsideTag(ChatMessage message, string outerTag, st

return rawmsg;
}

/// <summary>
/// Injects a tag around all found instances of a specific string in a ChatMessage.
/// </summary>
public static string InjectTagAroundString(ChatMessage message, string targetString, string tag, string? tagParameter)
{
var rawmsg = message.WrappedMessage;
rawmsg = Regex.Replace(rawmsg, "(?i)(" + targetString + ")(?-i)", $"[{tag}={tagParameter}]$1[/{tag}]");
return rawmsg;
}

public static string GetStringInsideTag(ChatMessage message, string tag)
{
var rawmsg = message.WrappedMessage;
Expand Down
30 changes: 30 additions & 0 deletions Content.Shared/Roles/RoleCodewordEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Robust.Shared.Serialization;

namespace Content.Shared.Roles;

/// <summary>
/// Raised on the server and sent to a client to record traitor codewords without exposing them to other clients.
/// </summary>
[Serializable, NetSerializable]
public sealed class RoleCodewordEvent : EntityEventArgs
{
public NetEntity Entity;
public Color Color;
public string RoleKey;
public List<string> Codewords;

/// <summary>
/// Raised on the server and sent to a client to record traitor codewords without exposing them to other clients.
/// </summary>
/// <param name="entity">The entity which the codewords should be assigned to.</param>
/// <param name="color">The color the keywords should be highlighted in.</param>
/// <param name="roleKey">The key used to distinguish the codewords for a specific role.</param>
/// <param name="codewords">The list of codewords.</param>
public RoleCodewordEvent(NetEntity entity, Color color, string roleKey, List<string> codewords)
{
Codewords = codewords;
Color = color;
RoleKey = roleKey;
Entity = entity;
}
}
6 changes: 1 addition & 5 deletions Resources/Prototypes/Datasets/verbs.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- type: dataset
- type: dataset
id: verbs
values:
- accept
Expand Down Expand Up @@ -97,9 +97,7 @@
- coach
- coil
- collect
- colour
- comb
SlamBamActionman marked this conversation as resolved.
Show resolved Hide resolved
- command
- communicate
- compare
- compete
Expand Down Expand Up @@ -544,7 +542,6 @@
- suffer
- suggest
- suit
- supply
- support
- suppose
- surprise
Expand Down Expand Up @@ -616,7 +613,6 @@
- whine
- whip
- whirl
- whisper
- whistle
- wink
- wipe
Expand Down
Loading