diff --git a/Content.Client/Chat/Managers/ChatManager.cs b/Content.Client/Chat/Managers/ChatManager.cs index 18f03cd7db0..27b126a5c04 100644 --- a/Content.Client/Chat/Managers/ChatManager.cs +++ b/Content.Client/Chat/Managers/ChatManager.cs @@ -47,6 +47,10 @@ public void SendMessage(string text, ChatSelectChannel channel) _consoleHost.ExecuteCommand($"me \"{CommandParsing.Escape(str)}\""); break; + case ChatSelectChannel.Subtle: // Floofstation + _consoleHost.ExecuteCommand($"subtle \"{CommandParsing.Escape(str)}\""); + break; + case ChatSelectChannel.Dead: if (_systems.GetEntitySystemOrNull() is {IsGhost: true}) goto case ChatSelectChannel.Local; @@ -76,7 +80,7 @@ public void SendMessage(string text, ChatSelectChannel channel) throw new ArgumentOutOfRangeException(nameof(channel), channel, null); } } - //Nyano - Summary: fires off the update permissions script. + //Nyano - Summary: fires off the update permissions script. public void UpdatePermissions() { PermissionsUpdated?.Invoke(); diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index f989fa0ee75..77e62ee5411 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -78,6 +78,7 @@ public sealed class ChatUIController : UIController {SharedChatSystem.OOCPrefix, ChatSelectChannel.OOC}, {SharedChatSystem.EmotesPrefix, ChatSelectChannel.Emotes}, {SharedChatSystem.EmotesAltPrefix, ChatSelectChannel.Emotes}, + {SharedChatSystem.SubtlePrefix, ChatSelectChannel.Subtle}, // Floofstation {SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin}, {SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio}, {SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}, @@ -92,6 +93,7 @@ public sealed class ChatUIController : UIController {ChatSelectChannel.LOOC, SharedChatSystem.LOOCPrefix}, {ChatSelectChannel.OOC, SharedChatSystem.OOCPrefix}, {ChatSelectChannel.Emotes, SharedChatSystem.EmotesPrefix}, + {ChatSelectChannel.Subtle, SharedChatSystem.SubtlePrefix}, // Floofstation {ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix}, {ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix}, {ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix}, @@ -496,6 +498,7 @@ private void UpdateChannelPermissions() FilterableChannels |= ChatChannel.Whisper; FilterableChannels |= ChatChannel.Radio; FilterableChannels |= ChatChannel.Emotes; + FilterableChannels |= ChatChannel.Subtle; // Floofstation FilterableChannels |= ChatChannel.Notifications; // Can only send local / radio / emote when attached to a non-ghost entity. @@ -506,6 +509,7 @@ private void UpdateChannelPermissions() CanSendChannels |= ChatSelectChannel.Whisper; CanSendChannels |= ChatSelectChannel.Radio; CanSendChannels |= ChatSelectChannel.Emotes; + CanSendChannels |= ChatSelectChannel.Subtle; // Floofstation } } diff --git a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorPopup.cs b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorPopup.cs index c1f3559d793..2137b173436 100644 --- a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorPopup.cs +++ b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorPopup.cs @@ -12,8 +12,9 @@ public sealed class ChannelSelectorPopup : Popup ChatSelectChannel.Local, ChatSelectChannel.Whisper, ChatSelectChannel.Emotes, + ChatSelectChannel.Subtle, // Floofstation ChatSelectChannel.Radio, - ChatSelectChannel.Telepathic, //Nyano - Summary: determines the order in which telepathic shows. + ChatSelectChannel.Telepathic, //Nyano - Summary: determines the order in which telepathic shows. ChatSelectChannel.LOOC, ChatSelectChannel.OOC, ChatSelectChannel.Dead, diff --git a/Content.Server/Chat/Commands/SubtleCommand.cs b/Content.Server/Chat/Commands/SubtleCommand.cs new file mode 100644 index 00000000000..a33bc0bc99e --- /dev/null +++ b/Content.Server/Chat/Commands/SubtleCommand.cs @@ -0,0 +1,43 @@ +using Content.Server.Chat.Systems; +using Content.Shared.Administration; +using Robust.Shared.Console; +using Robust.Shared.Enums; + +namespace Content.Server.Chat.Commands +{ + [AnyCommand] + internal sealed class SubtleCommand : IConsoleCommand + { + public string Command => "subtle"; + public string Description => "Perform an subtle action."; + public string Help => "subtle "; + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (shell.Player is not { } player) + { + shell.WriteError("This command cannot be run from the server."); + return; + } + + if (player.Status != SessionStatus.InGame) + return; + + if (player.AttachedEntity is not {} playerEntity) + { + shell.WriteError("You don't have an entity!"); + return; + } + + if (args.Length < 1) + return; + + var message = string.Join(" ", args).Trim(); + if (string.IsNullOrEmpty(message)) + return; + + IoCManager.Resolve().GetEntitySystem() + .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Subtle, ChatTransmitRange.NoGhosts, false, shell, player); + } + } +} diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index f69c95dfcb8..d286db3cc07 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -263,6 +263,9 @@ public void TrySendInGameICMessage( case InGameICChatType.Emote: SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); break; + case InGameICChatType.Subtle: + SendEntitySubtle(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); + break; //Nyano - Summary: case adds the telepathic chat sending ability. case InGameICChatType.Telepathic: _nyanoChatSystem.SendTelepathicChat(source, message, range == ChatTransmitRange.HideChat); @@ -596,6 +599,47 @@ private void SendEntityEmote( _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user}: {action}"); } + private void SendEntitySubtle( + EntityUid source, + string action, + ChatTransmitRange range, + string? nameOverride, + bool hideLog = false, + bool ignoreActionBlocker = false, + NetUserId? author = null + ) + { + if (!_actionBlocker.CanEmote(source) && !ignoreActionBlocker) + return; + + // get the entity's apparent name (if no override provided). + var ent = Identity.Entity(source, EntityManager); + string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent)); + + // Emotes use Identity.Name, since it doesn't actually involve your voice at all. + var wrappedMessage = Loc.GetString("chat-manager-entity-subtle-wrap-message", + ("entityName", name), + ("entity", ent), + ("message", FormattedMessage.RemoveMarkup(action))); + + foreach (var (session, data) in GetRecipients(source, WhisperClearRange)) + { + if (session.AttachedEntity is not { Valid: true } listener) + continue; + + if (MessageRangeCheck(session, data, range) == MessageRangeCheckResult.Disallowed) + continue; + + _chatManager.ChatMessageToOne(ChatChannel.Emotes, action, wrappedMessage, source, false, session.Channel); + } + + if (!hideLog) + if (name != Name(source)) + _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Subtle from {ToPrettyString(source):user} as {name}: {action}"); + else + _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Subtle from {ToPrettyString(source):user}: {action}"); + } + // ReSharper disable once InconsistentNaming private void SendLOOC(EntityUid source, ICommonSession player, string message, bool hideChat) { @@ -1012,6 +1056,7 @@ public enum InGameICChatType : byte Speak, Emote, Whisper, + Subtle, // FloofStation Telepathic //Nyano - Summary: adds telepathic as a type of message users can receive. } diff --git a/Content.Shared/Chat/ChatChannel.cs b/Content.Shared/Chat/ChatChannel.cs index d87fcbc075e..e80dcd82697 100644 --- a/Content.Shared/Chat/ChatChannel.cs +++ b/Content.Shared/Chat/ChatChannel.cs @@ -4,7 +4,7 @@ namespace Content.Shared.Chat /// Represents chat channels that the player can filter chat tabs by. /// [Flags] - public enum ChatChannel : ushort + public enum ChatChannel : UInt32 { None = 0, @@ -90,10 +90,15 @@ public enum ChatChannel : ushort /// Telepathic = 1 << 15, + /// + /// Subtle - Floofstation + /// + Subtle = 1 << 16, + /// /// Channels considered to be IC. /// - IC = Local | Whisper | Radio | Dead | Emotes | Damage | Visual | Telepathic | Notifications, //Nyano - Summary: Adds telepathic as an 'IC' labelled chat.. + IC = Local | Whisper | Radio | Dead | Emotes | Subtle | Damage | Visual | Telepathic | Notifications, //Nyano - Summary: Adds telepathic as an 'IC' labelled chat.. AdminRelated = Admin | AdminAlert | AdminChat, } diff --git a/Content.Shared/Chat/ChatSelectChannel.cs b/Content.Shared/Chat/ChatSelectChannel.cs index 5104bbc3068..16b7f61c41b 100644 --- a/Content.Shared/Chat/ChatSelectChannel.cs +++ b/Content.Shared/Chat/ChatSelectChannel.cs @@ -7,7 +7,7 @@ /// Maps to , giving better names. /// [Flags] - public enum ChatSelectChannel : ushort + public enum ChatSelectChannel : UInt32 { None = 0, @@ -41,6 +41,11 @@ public enum ChatSelectChannel : ushort /// Emotes = ChatChannel.Emotes, + /// + /// Subtle - Floofstation + /// + Subtle = ChatChannel.Subtle, + /// /// Deadchat /// @@ -52,7 +57,7 @@ public enum ChatSelectChannel : ushort Admin = ChatChannel.AdminChat, /// - /// Nyano - Summary:. Telepathic channel for all psionic entities. + /// Nyano - Summary:. Telepathic channel for all psionic entities. /// Telepathic = ChatChannel.Telepathic, diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs index 8d14adcc24b..9904e4b5254 100644 --- a/Content.Shared/Chat/SharedChatSystem.cs +++ b/Content.Shared/Chat/SharedChatSystem.cs @@ -19,9 +19,10 @@ public abstract class SharedChatSystem : EntitySystem public const char OOCPrefix = '['; public const char EmotesPrefix = '@'; public const char EmotesAltPrefix = '*'; + public const char SubtlePrefix = '-'; public const char AdminPrefix = ']'; public const char WhisperPrefix = ','; - public const char TelepathicPrefix = '='; //Nyano - Summary: Adds the telepathic channel's prefix. + public const char TelepathicPrefix = '='; //Nyano - Summary: Adds the telepathic channel's prefix. public const char DefaultChannelKey = 'h'; [ValidatePrototypeId] diff --git a/Resources/Locale/en-US/Floof/chat/ui/chat-box.ftl b/Resources/Locale/en-US/Floof/chat/ui/chat-box.ftl new file mode 100644 index 00000000000..affb4d3f20e --- /dev/null +++ b/Resources/Locale/en-US/Floof/chat/ui/chat-box.ftl @@ -0,0 +1,2 @@ +hud-chatbox-channel-Subtle = Subtle +hud-chatbox-select-channel-Subtle = Subtle diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl index fab815b4f90..a7f713ebcc6 100644 --- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl +++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl @@ -33,6 +33,11 @@ chat-manager-entity-me-wrap-message = [italic]{ PROPER($entity) -> [true] {$entityName} {$message}[/italic] } +chat-manager-entity-subtle-wrap-message = [italic]{ PROPER($entity) -> + *[false] the {$entityName} subtly {$message}[/italic] + [true] {$entityName} subtly {$message}[/italic] + } + chat-manager-entity-looc-wrap-message = LOOC: {$entityName}: {$message} chat-manager-send-ooc-wrap-message = OOC: {$playerName}: {$message} chat-manager-send-ooc-patron-wrap-message = OOC: [color={$patronColor}]{$playerName}[/color]: {$message}