diff --git a/Content.Client/Chat/Managers/ChatManager.cs b/Content.Client/Chat/Managers/ChatManager.cs index 67b5f5202f9fb8..0f038978ef735c 100644 --- a/Content.Client/Chat/Managers/ChatManager.cs +++ b/Content.Client/Chat/Managers/ChatManager.cs @@ -67,6 +67,12 @@ public void SendMessage(string text, ChatSelectChannel channel) _consoleHost.ExecuteCommand($"whisper \"{CommandParsing.Escape(str)}\""); break; + //ss220-telepathy-begin + case ChatSelectChannel.Telepathy: + _consoleHost.ExecuteCommand($"telepathy \"{CommandParsing.Escape(str)}\""); + break; + //ss220-telepathy-end + default: throw new ArgumentOutOfRangeException(nameof(channel), channel, null); } diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index 7767435c406e66..b251d372531123 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -20,6 +20,7 @@ using Content.Shared.Decals; using Content.Shared.Input; using Content.Shared.Radio; +using Content.Shared.SS220.Telepathy; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Input; @@ -79,7 +80,9 @@ public sealed class ChatUIController : UIController {SharedChatSystem.EmotesAltPrefix, ChatSelectChannel.Emotes}, {SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin}, {SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio}, - {SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead} + {SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}, + //ss220-telepathy + {SharedChatSystem.TelepathyChannelPrefix, ChatSelectChannel.Telepathy} }; public static readonly Dictionary ChannelPrefixes = new() @@ -92,7 +95,9 @@ public sealed class ChatUIController : UIController {ChatSelectChannel.Emotes, SharedChatSystem.EmotesPrefix}, {ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix}, {ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix}, - {ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix} + {ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix}, + //ss220-telepathy + {ChatSelectChannel.Telepathy, SharedChatSystem.TelepathyChannelPrefix} }; /// @@ -554,6 +559,14 @@ private void UpdateChannelPermissions() CanSendChannels |= ChatSelectChannel.Admin; } + //ss220-telepathy-begin + if (_ent.HasComponent(_player.LocalEntity)) + { + FilterableChannels |= ChatChannel.Telepathy; + CanSendChannels |= ChatSelectChannel.Telepathy; + } + //ss220-telepathy-end + SelectableChannels = CanSendChannels; // Necessary so that we always have a channel to fall back to. diff --git a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs index df4f56cb27cee1..262d9d4989bb75 100644 --- a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs +++ b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs @@ -16,6 +16,8 @@ public sealed partial class ChannelFilterPopup : Popup ChatChannel.Whisper, ChatChannel.Emotes, ChatChannel.Radio, + //ss220-telepathy + ChatChannel.Telepathy, ChatChannel.Notifications, ChatChannel.LOOC, ChatChannel.OOC, diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 2d08577e3bda61..b217b5e97726bb 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -24,6 +24,7 @@ using Content.Shared.Players; using Content.Shared.Radio; using Content.Shared.Speech; +using Content.Shared.SS220.Telepathy; using Content.Shared.Whitelist; using Robust.Server.Player; using Robust.Shared.Audio; @@ -260,6 +261,13 @@ public void TrySendInGameICMessage( case InGameICChatType.Emote: SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); break; + + //ss220-telepathy-begin + case InGameICChatType.Telepathy: + if (TryComp(source, out TelepathyComponent? telepathyComponent) && telepathyComponent.CanSend) + RaiseLocalEvent(source, new TelepathySendEvent() { Message = message }); + break; + //ss220-telepathy-end } } @@ -971,7 +979,9 @@ public enum InGameICChatType : byte { Speak, Emote, - Whisper + Whisper, + //ss220-telepathy + Telepathy } /// diff --git a/Content.Server/SS220/Chat/Command/Telepathy/TelepathyCommand.cs b/Content.Server/SS220/Chat/Command/Telepathy/TelepathyCommand.cs new file mode 100644 index 00000000000000..a190291a74a828 --- /dev/null +++ b/Content.Server/SS220/Chat/Command/Telepathy/TelepathyCommand.cs @@ -0,0 +1,51 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt + +using Content.Server.Chat.Systems; +using Content.Shared.Administration; +using Robust.Shared.Console; +using Robust.Shared.Enums; + +namespace Content.Server.SS220.Chat.Command.Telepathy; + +[AnyCommand] +public sealed class TelepathyCommand : IConsoleCommand +{ + public string Command => "telepathy"; + public string Description => "Send message through the power of mind"; + public string Help => $"{Command} "; + 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.Telepathy, + ChatTransmitRange.HideChat, + false, + shell, + player + ); + } +} diff --git a/Content.Server/SS220/Telepathy/TelepathySystem.cs b/Content.Server/SS220/Telepathy/TelepathySystem.cs new file mode 100644 index 00000000000000..212bbf97632a0b --- /dev/null +++ b/Content.Server/SS220/Telepathy/TelepathySystem.cs @@ -0,0 +1,93 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt + +using Content.Server.Chat.Systems; +using Content.Shared.Chat; +using Content.Shared.SS220.Telepathy; +using Robust.Shared.Network; +using Robust.Shared.Player; +using Robust.Shared.Utility; + +namespace Content.Server.SS220.Telepathy; + +/// +/// This handles events related to sending messages over the telepathy channel +/// +public sealed class TelepathySystem : EntitySystem +{ + [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + + /// + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnTelepathySend); + SubscribeLocalEvent(OnTelepathyAnnouncementSend); + } + + private void OnTelepathyAnnouncementSend(EntityUid uid, TelepathyComponent component, TelepathyAnnouncementSendEvent args) + { + SendMessageToEveryoneWithRightChannel(args.TelepathyChannel, args.Message, null); + } + + private void OnTelepathySend(EntityUid senderUid, TelepathyComponent component, TelepathySendEvent args) + { + if (!HasComp(senderUid)) + return; + + SendMessageToEveryoneWithRightChannel(component.TelepathyChannelPrototype, args.Message, senderUid); + } + + private void SendMessageToEveryoneWithRightChannel(string rightTelepathyChanel, string message, EntityUid? senderUid) + { + var telepathyQuery = EntityQueryEnumerator(); + while (telepathyQuery.MoveNext(out var receiverUid, out var receiverTelepathy)) + { + if (rightTelepathyChanel == receiverTelepathy.TelepathyChannelPrototype) + SendMessageToChat(receiverUid, message, senderUid); + } + } + + + private void SendMessageToChat(EntityUid receiverUid, string messageString, EntityUid? senderUid) + { + var name = GetSenderName(senderUid); + + var netSource = _entityManager.GetNetEntity(receiverUid); + var wrappedMessage = GetWrappedTelepathyMessage(receiverUid, messageString, senderUid); + var message = new ChatMessage( + ChatChannel.Telepathy, + messageString, + wrappedMessage, + netSource, + null + ); + if (TryComp(receiverUid, out ActorComponent? actor)) + _netMan.ServerSendMessage(new MsgChatMessage() {Message = message}, actor.PlayerSession.Channel); + } + + private string GetWrappedTelepathyMessage(EntityUid receiverUid, string messageString, EntityUid? senderUid) + { + if (senderUid == null) + { + return Loc.GetString( + "chat-manager-send-telepathy-announce", + ("announce", FormattedMessage.EscapeText(messageString)) + ); + } + + return Loc.GetString( + "chat-manager-send-telepathy-message", + ("message", FormattedMessage.EscapeText(messageString)), + ("senderName", GetSenderName(senderUid)) + ); + } + + private string GetSenderName(EntityUid? senderUid) + { + var nameEv = new TransformSpeakerNameEvent(senderUid!.Value, Name(senderUid.Value)); + RaiseLocalEvent(senderUid.Value, nameEv); + var name = nameEv.Name; + return name; + } +} diff --git a/Content.Shared/Chat/ChatChannel.cs b/Content.Shared/Chat/ChatChannel.cs index e8715a6ecb04d5..72ea70f928b121 100644 --- a/Content.Shared/Chat/ChatChannel.cs +++ b/Content.Shared/Chat/ChatChannel.cs @@ -85,10 +85,13 @@ public enum ChatChannel : ushort /// Unspecified = 1 << 14, + //ss220-telepathy + Telepathy = 1 << 15, + /// /// Channels considered to be IC. /// - IC = Local | Whisper | Radio | Dead | Emotes | Damage | Visual | Notifications, + IC = Local | Whisper | Radio | Dead | Emotes | Damage | Visual | Notifications | Telepathy, AdminRelated = Admin | AdminAlert | AdminChat, } diff --git a/Content.Shared/Chat/ChatSelectChannel.cs b/Content.Shared/Chat/ChatSelectChannel.cs index c18bb9b8ee31fe..20a4b15b06fa8f 100644 --- a/Content.Shared/Chat/ChatSelectChannel.cs +++ b/Content.Shared/Chat/ChatSelectChannel.cs @@ -51,6 +51,9 @@ public enum ChatSelectChannel : ushort /// Admin = ChatChannel.AdminChat, + //ss220-telepathy + Telepathy = ChatChannel.Telepathy, + Console = ChatChannel.Unspecified } } diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs index 40648e40f738d7..4e8e833ea1f704 100644 --- a/Content.Shared/Chat/SharedChatSystem.cs +++ b/Content.Shared/Chat/SharedChatSystem.cs @@ -22,6 +22,8 @@ public abstract class SharedChatSystem : EntitySystem public const char WhisperPrefix = ','; public const char EmotesAltPrefix = '*'; public const char DefaultChannelKey = 'р'; + //ss220-telepathy + public const char TelepathyChannelPrefix = '|'; [ValidatePrototypeId] public const string CommonChannel = "Common"; diff --git a/Content.Shared/SS220/Telepathy/TelepathyChannelPrototype.cs b/Content.Shared/SS220/Telepathy/TelepathyChannelPrototype.cs new file mode 100644 index 00000000000000..529b3c904897a2 --- /dev/null +++ b/Content.Shared/SS220/Telepathy/TelepathyChannelPrototype.cs @@ -0,0 +1,25 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt + +using Robust.Shared.Prototypes; + +namespace Content.Shared.SS220.Telepathy; + +[Prototype("telepathyChannel")] +public sealed partial class TelepathyChannelPrototype : IPrototype +{ + /// + /// Human-readable name for the channel. + /// + [DataField("name")] + public string Name { get; private set; } = string.Empty; + + [ViewVariables(VVAccess.ReadOnly)] + public string LocalizedName => Loc.GetString(Name); + + + [DataField("color")] + public Color Color { get; private set; } = Color.Lime; + + [IdDataField, ViewVariables] + public string ID { get; } = default!; +} diff --git a/Content.Shared/SS220/Telepathy/TelepathyComponent.cs b/Content.Shared/SS220/Telepathy/TelepathyComponent.cs new file mode 100644 index 00000000000000..ce16399f103361 --- /dev/null +++ b/Content.Shared/SS220/Telepathy/TelepathyComponent.cs @@ -0,0 +1,30 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt + +using Content.Shared.Actions; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.SS220.Telepathy; + +/// +/// This is used for giving telepathy ability +/// +[RegisterComponent] +public sealed partial class TelepathyComponent : Component +{ + [DataField("canSend", required: true)] + public bool CanSend; + + [DataField("telepathyChannelPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string TelepathyChannelPrototype; +} + +public sealed partial class TelepathySendEvent : InstantActionEvent +{ + public string Message { get; init; } +} + +public sealed partial class TelepathyAnnouncementSendEvent : InstantActionEvent +{ + public string Message { get; init; } + public string TelepathyChannel { get; init; } +} diff --git a/Resources/Locale/ru-RU/chat/managers/chat-manager.ftl b/Resources/Locale/ru-RU/chat/managers/chat-manager.ftl index 1b2449af6f98dd..b4a5eea15595a8 100644 --- a/Resources/Locale/ru-RU/chat/managers/chat-manager.ftl +++ b/Resources/Locale/ru-RU/chat/managers/chat-manager.ftl @@ -32,6 +32,8 @@ chat-manager-send-admin-dead-chat-wrap-message = { $adminChannelName }: [bold]([ chat-manager-send-admin-chat-wrap-message = { $adminChannelName }: [bold]{ $playerName }:[/bold] { $message } chat-manager-send-admin-announcement-wrap-message = [bold]{ $adminChannelName }: { $message }[/bold] chat-manager-send-hook-ooc-wrap-message = OOC: [bold](D){ $senderName }:[/bold] { $message } +chat-manager-send-telepathy-message = [color=purple]Эхо разума { $senderName }: { $message }[/color] +chat-manager-send-telepathy-announce = [color=purple]Эхо разума: { $announce }[/color] chat-manager-dead-channel-name = МЁРТВЫЕ chat-manager-admin-channel-name = АДМИН chat-manager-rate-limited = Вы отправляете сообщения слишком быстро! diff --git a/Resources/Locale/ru-RU/chat/ui/chat-box.ftl b/Resources/Locale/ru-RU/chat/ui/chat-box.ftl index dda8ff1aec2dc1..fb8f3cc375c8f0 100644 --- a/Resources/Locale/ru-RU/chat/ui/chat-box.ftl +++ b/Resources/Locale/ru-RU/chat/ui/chat-box.ftl @@ -14,9 +14,11 @@ hud-chatbox-select-channel-OOC = OOC hud-chatbox-select-channel-Damage = Повреждения hud-chatbox-select-channel-Visual = Действия hud-chatbox-select-channel-Radio = Рация +hud-chatbox-select-channel-Telepathy = Телепатия hud-chatbox-channel-Admin = Админ Разное hud-chatbox-channel-AdminAlert = Админ Уведомления hud-chatbox-channel-AdminChat = Админ Чат +hud-chatbox-channel-Telepathy = Телепатия hud-chatbox-channel-Dead = Мёртвые hud-chatbox-channel-Emotes = Эмоции hud-chatbox-channel-Local = Рядом diff --git a/Resources/Prototypes/SS220/telepahy_channels.yml b/Resources/Prototypes/SS220/telepahy_channels.yml new file mode 100644 index 00000000000000..a9aa17f5ecafc7 --- /dev/null +++ b/Resources/Prototypes/SS220/telepahy_channels.yml @@ -0,0 +1,3 @@ +- type: telepathyChannel + id: TelepathyChannelYogSothothCult + name: chat-telepathy-yogsothothcult