Skip to content

Commit

Permalink
Add codeword highlighting (space-wizards#30092)
Browse files Browse the repository at this point in the history
* Added codeword highlighting

* Updated to support more codeword roles, color is set serverside

* Review feedback

* Change to a Component-based system using SessionSpecific

* Tidied up CanGetState, set Access restrictions on component

* Clean-up

* Makes the injection ignore brackets, restore some codewords, remove "Taste/Touch" from adjectives
  • Loading branch information
SlamBamActionman authored and sleepyyapril committed Dec 28, 2024
1 parent 8322ccf commit ad59231
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 5 deletions.
8 changes: 8 additions & 0 deletions Content.Client/Roles/RoleCodewordSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared.Roles.RoleCodeword;

namespace Content.Client.Roles;

public sealed class RoleCodewordSystem : SharedRoleCodewordSystem
{

}
18 changes: 18 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 All @@ -21,6 +23,7 @@
using Content.Shared.Examine;
using Content.Shared.Input;
using Content.Shared.Radio;
using Content.Shared.Roles.RoleCodeword;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
Expand Down Expand Up @@ -62,6 +65,8 @@ public sealed class ChatUIController : UIController
[UISystemDependency] private readonly ChatSystem? _chatSys = default;
[UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //Nyano - Summary: makes the psionic chat available.
[UISystemDependency] private readonly TransformSystem? _transform = default;
[UISystemDependency] private readonly MindSystem? _mindSystem = default!;
[UISystemDependency] private readonly RoleCodewordSystem? _roleCodewordSystem = default!;

[ValidatePrototypeId<ColorPalettePrototype>]
private const string ChatNamePalette = "ChatNames";
Expand Down Expand Up @@ -833,6 +838,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 && _roleCodewordSystem != 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
14 changes: 12 additions & 2 deletions Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
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 Content.Shared.Roles.RoleCodeword;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using System.Linq;
Expand All @@ -25,6 +27,8 @@ namespace Content.Server.GameTicking.Rules;

public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
{
private static readonly Color TraitorCodewordColor = Color.FromHex("#cc3b3b");

[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
Expand All @@ -34,6 +38,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
[Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly SharedJobSystem _jobs = default!;
[Dependency] private readonly ObjectivesSystem _objectives = default!;
[Dependency] private readonly SharedRoleCodewordSystem _roleCodewordSystem = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -120,12 +125,17 @@ public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component)
Briefing = briefing
}, mind, true);

// Don't Change the faction, this was stupid.
// Send codewords to only the traitor client
var color = TraitorCodewordColor; // Fall back to a dark red Syndicate color if a prototype is not found

RoleCodewordComponent codewordComp = EnsureComp<RoleCodewordComponent>(mindId);
_roleCodewordSystem.SetRoleCodewords(codewordComp, "traitor", component.Codewords.ToList(), color);

// Don't change the faction, this was stupid.
//_npcFaction.RemoveFaction(traitor, component.NanoTrasenFaction, false);
//_npcFaction.AddFaction(traitor, component.SyndicateFaction);

RaiseLocalEvent(traitor, new MoodEffectEvent("TraitorFocused"));

return true;
}

Expand Down
8 changes: 8 additions & 0 deletions Content.Server/Roles/RoleCodeword/RoleCodewordSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared.Roles.RoleCodeword;

namespace Content.Server.Roles.RoleCodeword;

public sealed class RoleCodewordSystem : SharedRoleCodewordSystem
{

}
13 changes: 13 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 @@ -239,6 +240,18 @@ 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.
/// Excludes strings inside other tags and brackets.
/// </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
37 changes: 37 additions & 0 deletions Content.Shared/Roles/RoleCodeword/RoleCodewordComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;

namespace Content.Shared.Roles.RoleCodeword;

/// <summary>
/// Used to display and highlight codewords in chat messages on the client.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedRoleCodewordSystem), Other = AccessPermissions.Read)]
public sealed partial class RoleCodewordComponent : Component
{
/// <summary>
/// Contains the codewords tied to a role.
/// Key string should be unique for the role.
/// </summary>
[DataField, AutoNetworkedField]
public Dictionary<string, CodewordsData> RoleCodewords = new();

public override bool SessionSpecific => true;
}

[DataDefinition, Serializable, NetSerializable]
public partial struct CodewordsData
{
[DataField]
public Color Color;

[DataField]
public List<string> Codewords;

public CodewordsData(Color color, List<string> codewords)
{
Color = color;
Codewords = codewords;
}
}
49 changes: 49 additions & 0 deletions Content.Shared/Roles/RoleCodeword/SharedRoleCodewordSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Content.Shared.Mind;
using Robust.Shared.GameStates;
using Robust.Shared.Player;

namespace Content.Shared.Roles.RoleCodeword;

public abstract class SharedRoleCodewordSystem : EntitySystem
{
[Dependency] private readonly SharedMindSystem _mindSystem = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<RoleCodewordComponent, ComponentGetStateAttemptEvent>(OnCodewordCompGetStateAttempt);
}

/// <summary>
/// Determines if a codeword component should be sent to the client.
/// </summary>
private void OnCodewordCompGetStateAttempt(EntityUid uid, RoleCodewordComponent comp, ref ComponentGetStateAttemptEvent args)
{
args.Cancelled = !CanGetState(args.Player, comp);
}

/// <summary>
/// The criteria that determine whether a codeword component should be sent to a client.
/// Sends the component if its owner is the player mind.
/// </summary>
/// <param name="player"> The Player the component will be sent to.</param>
/// <param name="comp"> The component being checked against</param>
/// <returns></returns>
private bool CanGetState(ICommonSession? player, RoleCodewordComponent comp)
{
if (!_mindSystem.TryGetMind(player, out EntityUid mindId, out var _))
return false;

if (!TryComp(mindId, out RoleCodewordComponent? playerComp) && comp != playerComp)
return false;

return true;
}

public void SetRoleCodewords(RoleCodewordComponent comp, string key, List<string> codewords, Color color)
{
var data = new CodewordsData(color, codewords);
comp.RoleCodewords[key] = data;
}
}
1 change: 0 additions & 1 deletion Resources/Prototypes/Datasets/adjectives.yml
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,6 @@
- slow
- swift
- young
- Taste/Touch
- bitter
- delicious
- fresh
Expand Down
3 changes: 1 addition & 2 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 @@ -616,7 +616,6 @@
- whine
- whip
- whirl
- whisper
- whistle
- wink
- wipe
Expand Down

0 comments on commit ad59231

Please sign in to comment.