From 92dcd724d4d6dc3e006bd1d11c9385a9829a1e9e Mon Sep 17 00:00:00 2001 From: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Date: Fri, 26 Jul 2024 23:11:42 +0300 Subject: [PATCH] Refactor Sign Languages and Language Markers (#575) # Description This refactors #510 and #553. #553 specifically was reverted and re-implemented from scratch. As a consequence to all of this, the chat system was refactored a bit too, hopefully for the best. Changes: - InGameICChatType, InGameOOCChatType, ChatTransmitRange were all moved to shared and made serializable - Added a method to wrap whisper messages to reduce code duplication in chat system - Both WrapPublicMethod and WrapWhisperMessage call the same generic WrapMessage method, which allows to add speech verbs to whispers and more. That method is also fully responsible for adding language markers and deducing speech verbs now. - Everything related to speech was moved out of LanguagePrototype and into SpeechOverrideInfo. LanguagePrototype now holds an instance of that. - Added AllowRadio, RequireSpeech, ChatTypeOverride, SpeechVerbOverrides, MessageWrapOverrides to SpeechOverrideInfo, all of which are used in implementing the sign language. - Suffered a lot # TODO - [X] Cry - [X] Fix the sign language not displaying properly over the character. - [X] Find a way to circumvent being unable to speak??

Media

![image](https://github.com/user-attachments/assets/845ec5d3-20aa-4786-bdc8-c39c80e0a4a3) See below

# Changelog No cl no fun --------- Signed-off-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Co-authored-by: Danger Revolution! <142105406+DangerRevolution@users.noreply.github.com> --- .../Administration/Commands/DSay.cs | 1 + .../Administration/Commands/OSay.cs | 1 + .../EntitySystems/AdvertiseSystem.cs | 1 + .../EntitySystems/SpeakOnUIClosedSystem.cs | 1 + Content.Server/Chat/Commands/LOOCCommand.cs | 1 + Content.Server/Chat/Commands/MeCommand.cs | 1 + Content.Server/Chat/Commands/SayCommand.cs | 1 + .../Chat/Commands/WhisperCommand.cs | 1 + .../Chat/Systems/AutoEmoteSystem.cs | 1 + .../Chat/Systems/ChatSystem.Emote.cs | 4 +- Content.Server/Chat/Systems/ChatSystem.cs | 195 +++++++----------- .../Chat/Systems/EmoteOnDamageSystem.cs | 2 + .../Chemistry/ReagentEffects/Emote.cs | 1 + Content.Server/Cloning/CloningSystem.cs | 3 +- Content.Server/Cluwne/CluwneSystem.cs | 1 + .../DeltaV/NPC/Roboisseur/RoboisseurSystem.cs | 1 + .../Language/Commands/SayLanguageCommand.cs | 1 + Content.Server/Magic/MagicSystem.cs | 1 + Content.Server/Medical/DefibrillatorSystem.cs | 1 + Content.Server/Mobs/CritMobActionsSystem.cs | 1 + .../PrimitiveTasks/Operators/SpeakOperator.cs | 1 + .../Specific/MedibotInjectOperator.cs | 1 + .../Nyanotrasen/Chat/TSayCommand.cs | 1 + Content.Server/Nyanotrasen/Mail/MailSystem.cs | 1 + .../SophicScribe/SophicScribeSystem.cs | 1 + .../Radio/EntitySystems/RadioSystem.cs | 12 +- Content.Server/RatKing/RatKingSystem.cs | 1 + Content.Server/Speech/Muting/MutingSystem.cs | 7 +- .../Speech/Systems/RandomBarkSystem.cs | 1 + .../SurveillanceCameraSpeakerSystem.cs | 1 + .../Weapons/Melee/MeleeWeaponSystem.cs | 1 + Content.Shared/Chat/SharedChatSystem.cs | 42 +++- Content.Shared/Language/LanguagePrototype.cs | 67 ++++-- .../Locale/en-US/language/languages-sign.ftl | 6 + Resources/Locale/en-US/language/languages.ftl | 6 +- .../Locale/en-US/language/sign-language.ftl | 4 - Resources/Prototypes/Language/languages.yml | 66 ++++-- 37 files changed, 267 insertions(+), 172 deletions(-) create mode 100644 Resources/Locale/en-US/language/languages-sign.ftl delete mode 100644 Resources/Locale/en-US/language/sign-language.ftl diff --git a/Content.Server/Administration/Commands/DSay.cs b/Content.Server/Administration/Commands/DSay.cs index 61b47d78567..935387d24f1 100644 --- a/Content.Server/Administration/Commands/DSay.cs +++ b/Content.Server/Administration/Commands/DSay.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Shared.Console; namespace Content.Server.Administration.Commands diff --git a/Content.Server/Administration/Commands/OSay.cs b/Content.Server/Administration/Commands/OSay.cs index 2f17bd9d70a..9c5a20ef693 100644 --- a/Content.Server/Administration/Commands/OSay.cs +++ b/Content.Server/Administration/Commands/OSay.cs @@ -2,6 +2,7 @@ using Content.Server.Administration.Logs; using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Content.Shared.Database; using Robust.Shared.Console; diff --git a/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs b/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs index 28fa01628f4..e34506deac4 100644 --- a/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs +++ b/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Advertise.Components; using Content.Server.Chat.Systems; using Content.Server.Power.Components; +using Content.Shared.Chat; using Content.Shared.VendingMachines; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs b/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs index 048f59b8d33..939fc9a2dbb 100644 --- a/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs +++ b/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Chat.Systems; using Content.Server.UserInterface; using Content.Shared.Advertise; +using Content.Shared.Chat; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Server/Chat/Commands/LOOCCommand.cs b/Content.Server/Chat/Commands/LOOCCommand.cs index 9e16193fc38..c347f14bd1c 100644 --- a/Content.Server/Chat/Commands/LOOCCommand.cs +++ b/Content.Server/Chat/Commands/LOOCCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Shared.Console; using Robust.Shared.Enums; diff --git a/Content.Server/Chat/Commands/MeCommand.cs b/Content.Server/Chat/Commands/MeCommand.cs index e763d5656e1..9dff32b6579 100644 --- a/Content.Server/Chat/Commands/MeCommand.cs +++ b/Content.Server/Chat/Commands/MeCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Shared.Console; using Robust.Shared.Enums; diff --git a/Content.Server/Chat/Commands/SayCommand.cs b/Content.Server/Chat/Commands/SayCommand.cs index 273f908c9ab..a31ddbdb7a2 100644 --- a/Content.Server/Chat/Commands/SayCommand.cs +++ b/Content.Server/Chat/Commands/SayCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Shared.Console; using Robust.Shared.Enums; diff --git a/Content.Server/Chat/Commands/WhisperCommand.cs b/Content.Server/Chat/Commands/WhisperCommand.cs index c88e2519ee6..db967dbbb2d 100644 --- a/Content.Server/Chat/Commands/WhisperCommand.cs +++ b/Content.Server/Chat/Commands/WhisperCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Shared.Console; using Robust.Shared.Enums; diff --git a/Content.Server/Chat/Systems/AutoEmoteSystem.cs b/Content.Server/Chat/Systems/AutoEmoteSystem.cs index 3d6bd535401..8e02f7f53f1 100644 --- a/Content.Server/Chat/Systems/AutoEmoteSystem.cs +++ b/Content.Server/Chat/Systems/AutoEmoteSystem.cs @@ -1,4 +1,5 @@ using System.Linq; +using Content.Shared.Chat; using Content.Shared.Chat.Prototypes; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Server/Chat/Systems/ChatSystem.Emote.cs b/Content.Server/Chat/Systems/ChatSystem.Emote.cs index bd1b944db30..c18b945ec6f 100644 --- a/Content.Server/Chat/Systems/ChatSystem.Emote.cs +++ b/Content.Server/Chat/Systems/ChatSystem.Emote.cs @@ -1,5 +1,6 @@ using System.Collections.Frozen; using System.Linq; +using Content.Shared.Chat; using Content.Shared.Chat.Prototypes; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -87,7 +88,8 @@ public void TryEmoteWithChat( { // not all emotes are loc'd, but for the ones that are we pass in entity var action = Loc.GetString(_random.Pick(emote.ChatMessages), ("entity", source)); - SendEntityEmote(source, action, range, nameOverride, hideLog: hideLog, checkEmote: false, ignoreActionBlocker: ignoreActionBlocker); + var language = _language.GetLanguage(source); + SendEntityEmote(source, action, range, nameOverride, language, hideLog: hideLog, checkEmote: false, ignoreActionBlocker: ignoreActionBlocker); } // do the rest of emote event logic here diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 05342dbe3c0..022520abeb0 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -6,12 +6,9 @@ using Content.Server.Chat.Managers; using Content.Server.GameTicking; using Content.Server.Language; -using Content.Server.Speech; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; using Content.Server.Nyanotrasen.Chat; -using Content.Server.Speech.Components; -using Content.Server.Speech.EntitySystems; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Shared.ActionBlocker; @@ -20,9 +17,9 @@ using Content.Shared.Database; using Content.Shared.Ghost; using Content.Shared.Language; -using Content.Shared.Humanoid; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; +using Content.Shared.Language.Systems; using Content.Shared.Mobs.Systems; using Content.Shared.Players; using Content.Shared.Radio; @@ -45,6 +42,10 @@ namespace Content.Server.Chat.Systems; +// Dear contributor. When I was introducing changes to this system only god and I knew what I was doing. +// Now only god knows. Please don't touch this code ever again. If you do have to, increment this counter as a warning for others: +// TOTAL_HOURS_WASTED_HERE_EE = 17 + // TODO refactor whatever active warzone this class and chatmanager have become /// /// ChatSystem is responsible for in-simulation chat handling, such as whispering, speaking, emoting, etc. @@ -227,6 +228,8 @@ public void TrySendInGameICMessage( message = message[1..]; } + var language = languageOverride ?? _language.GetLanguage(source); + bool shouldCapitalize = (desiredType != InGameICChatType.Emote); bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); // Capitalizing the word I only happens in English, so we check language here @@ -238,30 +241,23 @@ public void TrySendInGameICMessage( // Was there an emote in the message? If so, send it. if (player != null && emoteStr != message && emoteStr != null) { - SendEntityEmote(source, emoteStr, range, nameOverride, ignoreActionBlocker); + SendEntityEmote(source, emoteStr, range, nameOverride, language, ignoreActionBlocker); } // This can happen if the entire string is sanitized out. if (string.IsNullOrEmpty(message)) return; - // Check if the message is in sign language - if (desiredType == InGameICChatType.Speak || desiredType == InGameICChatType.Whisper) - { - var language = languageOverride ?? _language.GetLanguage(source); - if (language.SignLanguage ?? false) - { - SendEntityEmote(source, message, range, nameOverride, ignoreActionBlocker, signLanguage: true, languageOverride: languageOverride); - return; - } - } + // This is really terrible. I hate myself for doing this. + if (language.SpeechOverride.ChatTypeOverride is { } chatTypeOverride) + desiredType = chatTypeOverride; // This message may have a radio prefix, and should then be whispered to the resolved radio channel if (checkRadioPrefix) { if (TryProccessRadioMessage(source, message, out var modMessage, out var channel)) { - SendEntityWhisper(source, modMessage, range, channel, nameOverride, hideLog, ignoreActionBlocker); + SendEntityWhisper(source, modMessage, range, channel, nameOverride, language, hideLog, ignoreActionBlocker); return; } } @@ -270,13 +266,13 @@ public void TrySendInGameICMessage( switch (desiredType) { case InGameICChatType.Speak: - SendEntitySpeak(source, message, range, nameOverride, hideLog, ignoreActionBlocker, languageOverride: languageOverride); + SendEntitySpeak(source, message, range, nameOverride, language, hideLog, ignoreActionBlocker); break; case InGameICChatType.Whisper: - SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker, languageOverride: languageOverride); + SendEntityWhisper(source, message, range, null, nameOverride, language, hideLog, ignoreActionBlocker); break; case InGameICChatType.Emote: - SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); + SendEntityEmote(source, message, range, nameOverride, language, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); break; //Nyano - Summary: case adds the telepathic chat sending ability. case InGameICChatType.Telepathic: @@ -402,16 +398,16 @@ private void SendEntitySpeak( string originalMessage, ChatTransmitRange range, string? nameOverride, + LanguagePrototype language, bool hideLog = false, - bool ignoreActionBlocker = false, - LanguagePrototype? languageOverride = null + bool ignoreActionBlocker = false ) { if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker) return; // The original message - var message = TransformSpeech(source, FormattedMessage.RemoveMarkup(originalMessage)); + var message = TransformSpeech(source, FormattedMessage.RemoveMarkup(originalMessage), language); if (message.Length == 0) return; @@ -434,15 +430,13 @@ private void SendEntitySpeak( speech = proto; } - var language = languageOverride ?? _language.GetLanguage(source); - name = FormattedMessage.EscapeText(name); // The chat message wrapped in a "x says y" string - var wrappedMessage = WrapPublicMessage(source, name, message, languageOverride: language); + var wrappedMessage = WrapPublicMessage(source, name, message, language: language); // The chat message obfuscated via language obfuscation var obfuscated = SanitizeInGameICMessage(source, _language.ObfuscateSpeech(message, language), out var emoteStr, true, _configurationManager.GetCVar(CCVars.ChatPunctuation), (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en")); // The language-obfuscated message wrapped in a "x says y" string - var wrappedObfuscated = WrapPublicMessage(source, name, obfuscated, languageOverride: language); + var wrappedObfuscated = WrapPublicMessage(source, name, obfuscated, language: language); SendInVoiceRange(ChatChannel.Local, name, message, wrappedMessage, obfuscated, wrappedObfuscated, source, range, languageOverride: language); @@ -478,15 +472,15 @@ private void SendEntityWhisper( ChatTransmitRange range, RadioChannelPrototype? channel, string? nameOverride, + LanguagePrototype language, bool hideLog = false, - bool ignoreActionBlocker = false, - LanguagePrototype? languageOverride = null + bool ignoreActionBlocker = false ) { if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker) return; - var message = TransformSpeech(source, FormattedMessage.RemoveMarkup(originalMessage)); + var message = TransformSpeech(source, FormattedMessage.RemoveMarkup(originalMessage), language); if (message.Length == 0) return; @@ -506,7 +500,6 @@ private void SendEntityWhisper( } name = FormattedMessage.EscapeText(name); - var language = languageOverride ?? _language.GetLanguage(source); var languageObfuscatedMessage = SanitizeInGameICMessage(source, _language.ObfuscateSpeech(message, language), out var emoteStr, true, _configurationManager.GetCVar(CCVars.ChatPunctuation), (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en")); foreach (var (session, data) in GetRecipients(source, Transform(source).GridUid == null ? 0.3f : WhisperMuffledRange)) @@ -523,7 +516,7 @@ private void SendEntityWhisper( var canUnderstandLanguage = _language.CanUnderstand(listener, language.ID); // How the entity perceives the message depends on whether it can understand its language - var perceivedMessage = canUnderstandLanguage ? message : languageObfuscatedMessage; + var perceivedMessage = FormattedMessage.EscapeText(canUnderstandLanguage ? message : languageObfuscatedMessage); // Result is the intermediate message derived from the perceived one via obfuscation // Wrapped message is the result wrapped in an "x says y" string @@ -532,33 +525,26 @@ private void SendEntityWhisper( { // Scenario 1: the listener can clearly understand the message result = perceivedMessage; - wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("color", language.Color ?? Color.Gray), - ("entityName", name), - ("message", FormattedMessage.EscapeText(result))); + wrappedMessage = WrapWhisperMessage(source, "chat-manager-entity-whisper-wrap-message", name, perceivedMessage, language); } else if (_interactionSystem.InRangeUnobstructed(source, listener, WhisperMuffledRange, Shared.Physics.CollisionGroup.Opaque)) { // Scenerio 2: if the listener is too far, they only hear fragments of the message - // Collisiongroup.Opaque is not ideal for this use. Preferably, there should be a check specifically with "Can Ent1 see Ent2" in mind result = ObfuscateMessageReadability(perceivedMessage); - wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("entityName", nameIdentity), ("color", language.Color ?? Color.Gray), ("message", FormattedMessage.EscapeText(result))); + wrappedMessage = WrapWhisperMessage(source, "chat-manager-entity-whisper-wrap-message", nameIdentity, perceivedMessage, language); } else { // Scenario 3: If listener is too far and has no line of sight, they can't identify the whisperer's identity result = ObfuscateMessageReadability(perceivedMessage); - wrappedMessage = Loc.GetString("chat-manager-entity-whisper-unknown-wrap-message", - ("color", language.Color ?? Color.Gray), - ("message", FormattedMessage.EscapeText(result))); + wrappedMessage = WrapWhisperMessage(source, "chat-manager-entity-whisper-unknown-wrap-message", string.Empty, perceivedMessage, language); } _chatManager.ChatMessageToOne(ChatChannel.Whisper, result, wrappedMessage, source, false, session.Channel); } var replayWrap = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("color", language.Color ?? Color.Gray), + ("color", language.SpeechOverride.Color), ("entityName", name), ("message", FormattedMessage.EscapeText(message))); _replay.RecordServerMessage(new ChatMessage(ChatChannel.Whisper, message, replayWrap, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); @@ -589,12 +575,11 @@ private void SendEntityEmote( string action, ChatTransmitRange range, string? nameOverride, + LanguagePrototype language, bool hideLog = false, bool checkEmote = true, bool ignoreActionBlocker = false, - NetUserId? author = null, - LanguagePrototype? languageOverride = null, - bool? signLanguage = false + NetUserId? author = null ) { if (!_actionBlocker.CanEmote(source) && !ignoreActionBlocker) @@ -604,32 +589,15 @@ private void SendEntityEmote( var ent = Identity.Entity(source, EntityManager); string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent)); - var language = languageOverride ?? _language.GetLanguage(source); - // Emotes use Identity.Name, since it doesn't actually involve your voice at all. - var wrappedMessage = ""; - var obfuscatedWrappedMessage = ""; - if (signLanguage == true) - { - wrappedMessage = Loc.GetString("entity-signlanguage-message", - ("entityName", name), - ("message", FormattedMessage.EscapeText(action))); - - obfuscatedWrappedMessage = Loc.GetString(_language.ObfuscateSpeech(action, language), - ("entityName", name)); - } - else - { - wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message", - ("entityName", name), - ("entity", ent), - ("message", FormattedMessage.RemoveMarkup(action))); - - } + var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message", + ("entityName", name), + ("entity", ent), + ("message", FormattedMessage.RemoveMarkup(action))); if (checkEmote) TryEmoteChatInput(source, action); - SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage, source, range, author, signLanguage: true); + SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage: "", source, range, author); if (!hideLog) if (name != Name(source)) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}"); @@ -743,7 +711,7 @@ private MessageRangeCheckResult MessageRangeCheck(ICommonSession session, ICChat /// /// Sends a chat message to the given players in range of the source entity. /// - private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null, bool? signLanguage = false) + private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null) { var language = languageOverride ?? _language.GetLanguage(source); foreach (var (session, data) in GetRecipients(source, Transform(source).GridUid == null ? 0.3f : VoiceRange)) @@ -761,17 +729,9 @@ private void SendInVoiceRange(ChatChannel channel, string name, string message, continue; EntityUid listener = session.AttachedEntity.Value; - // Quickly Checking if the Emote is a real one or Sign Language. - var notSignLanguage = false; - if (channel == ChatChannel.Emotes) - { - notSignLanguage = true; - if (signLanguage == true) - notSignLanguage = false; - } // If the channel does not support languages, or the entity can understand the message, send the original message, otherwise send the obfuscated version - if (channel == ChatChannel.LOOC || notSignLanguage || _language.CanUnderstand(listener, language.ID)) + if (channel == ChatChannel.LOOC || channel == ChatChannel.Emotes || _language.CanUnderstand(listener, language.ID)) { _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author); } @@ -836,8 +796,11 @@ private string SanitizeInGameOOCMessage(string message) return newMessage; } - public string TransformSpeech(EntityUid sender, string message) + public string TransformSpeech(EntityUid sender, string message, LanguagePrototype language) { + if (!language.SpeechOverride.RequireSpeech) + return message; // Do not apply speech accents if there's no speech involved. + var ev = new TransformSpeechEvent(sender, message); RaiseLocalEvent(ev); @@ -891,16 +854,40 @@ public string SanitizeMessageReplaceWords(string message) /// /// Wraps a message sent by the specified entity into an "x says y" string. /// - public string WrapPublicMessage(EntityUid source, string name, string message, LanguagePrototype? languageOverride = null) + public string WrapPublicMessage(EntityUid source, string name, string message, LanguagePrototype? language = null) { - var language = languageOverride ?? _language.GetLanguage(source); + var wrapId = GetSpeechVerb(source, message).Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message"; + return WrapMessage(wrapId, InGameICChatType.Speak, source, name, message, language); + } + + /// + /// Wraps a message whispered by the specified entity into an "x whispers y" string. + /// + public string WrapWhisperMessage(EntityUid source, LocId defaultWrap, string entityName, string message, LanguagePrototype? language = null) + { + return WrapMessage(defaultWrap, InGameICChatType.Whisper, source, entityName, message, language); + } + + /// + /// Wraps a message sent by the specified entity into the specified wrap string. + /// + public string WrapMessage(LocId wrapId, InGameICChatType chatType, EntityUid source, string entityName, string message, LanguagePrototype? language) + { + language ??= _language.GetLanguage(source); + if (language.SpeechOverride.MessageWrapOverrides.TryGetValue(chatType, out var wrapOverride)) + wrapId = wrapOverride; + var speech = GetSpeechVerb(source, message); - return Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", - ("color", language.Color ?? Color.White), - ("entityName", name), - ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), - ("fontType", language.FontId ?? speech.FontId), - ("fontSize", language.FontSize ?? speech.FontSize), + var verbId = language.SpeechOverride.SpeechVerbOverrides is { } verbsOverride + ? _random.Pick(verbsOverride).ToString() + : _random.Pick(speech.SpeechVerbStrings); + + return Loc.GetString(wrapId, + ("color", language.SpeechOverride.Color), + ("entityName", entityName), + ("verb", Loc.GetString(verbId)), + ("fontType", language.SpeechOverride.FontId ?? speech.FontId), + ("fontSize", language.SpeechOverride.FontSize ?? speech.FontSize), ("message", message)); } @@ -1070,39 +1057,3 @@ public EntitySpokeEvent(EntityUid source, string message, RadioChannelPrototype? Language = language; } } - -/// -/// InGame IC chat is for chat that is specifically ingame (not lobby) but is also in character, i.e. speaking. -/// -// ReSharper disable once InconsistentNaming -public enum InGameICChatType : byte -{ - Speak, - Emote, - Whisper, - Telepathic //Nyano - Summary: adds telepathic as a type of message users can receive. -} - -/// -/// InGame OOC chat is for chat that is specifically ingame (not lobby) but is OOC, like deadchat or LOOC. -/// -public enum InGameOOCChatType : byte -{ - Looc, - Dead -} - -/// -/// Controls transmission of chat. -/// -public enum ChatTransmitRange : byte -{ - /// Acts normal, ghosts can hear across the map, etc. - Normal, - /// Normal but ghosts are still range-limited. - GhostRangeLimit, - /// Hidden from the chat window. - HideChat, - /// Ghosts can't hear or see it at all. Regular players can if in-range. - NoGhosts -} diff --git a/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs b/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs index 878c517d924..98ba415b968 100644 --- a/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs +++ b/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs @@ -1,3 +1,5 @@ +using Content.Shared.Chat; + namespace Content.Server.Chat.Systems; using Content.Shared.Chat.Prototypes; diff --git a/Content.Server/Chemistry/ReagentEffects/Emote.cs b/Content.Server/Chemistry/ReagentEffects/Emote.cs index a4d49e4ad1c..729f0671217 100644 --- a/Content.Server/Chemistry/ReagentEffects/Emote.cs +++ b/Content.Server/Chemistry/ReagentEffects/Emote.cs @@ -1,4 +1,5 @@ using Content.Server.Chat.Systems; +using Content.Shared.Chat; using Content.Shared.Chat.Prototypes; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; diff --git a/Content.Server/Cloning/CloningSystem.cs b/Content.Server/Cloning/CloningSystem.cs index 00612833676..92e658591a0 100644 --- a/Content.Server/Cloning/CloningSystem.cs +++ b/Content.Server/Cloning/CloningSystem.cs @@ -49,6 +49,7 @@ using Content.Shared.SSDIndicator; using Content.Shared.Damage.ForceSay; using Content.Server.Polymorph.Components; +using Content.Shared.Chat; namespace Content.Server.Cloning { @@ -248,7 +249,7 @@ public bool TryCloning(EntityUid uid, EntityUid bodyToClone, Entity(mob); diff --git a/Content.Server/Cluwne/CluwneSystem.cs b/Content.Server/Cluwne/CluwneSystem.cs index c170886a803..bd7b7a66201 100644 --- a/Content.Server/Cluwne/CluwneSystem.cs +++ b/Content.Server/Cluwne/CluwneSystem.cs @@ -12,6 +12,7 @@ using Robust.Shared.Prototypes; using Content.Server.Emoting.Systems; using Content.Server.Speech.EntitySystems; +using Content.Shared.Chat; using Content.Shared.Cluwne; using Content.Shared.Interaction.Components; using Robust.Shared.Audio; diff --git a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs index 69bd37e674d..b4e99e6199d 100644 --- a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs +++ b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Kitchen; using Robust.Server.GameObjects; using Content.Server.Materials; +using Content.Shared.Chat; using Robust.Shared.Player; using Robust.Shared.Timing; diff --git a/Content.Server/Language/Commands/SayLanguageCommand.cs b/Content.Server/Language/Commands/SayLanguageCommand.cs index 2304781fa04..caca2f41cf8 100644 --- a/Content.Server/Language/Commands/SayLanguageCommand.cs +++ b/Content.Server/Language/Commands/SayLanguageCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Shared.Console; using Robust.Shared.Enums; diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index 86555924712..18602c3de8b 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -7,6 +7,7 @@ using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Actions; using Content.Shared.Body.Components; +using Content.Shared.Chat; using Content.Shared.Coordinates.Helpers; using Content.Shared.DoAfter; using Content.Shared.Doors.Components; diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs index bf2f8805326..7b0b4110201 100644 --- a/Content.Server/Medical/DefibrillatorSystem.cs +++ b/Content.Server/Medical/DefibrillatorSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Ghost; using Content.Server.Popups; using Content.Server.PowerCell; +using Content.Shared.Chat; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.Interaction; diff --git a/Content.Server/Mobs/CritMobActionsSystem.cs b/Content.Server/Mobs/CritMobActionsSystem.cs index c897102dca7..963bd98d0f4 100644 --- a/Content.Server/Mobs/CritMobActionsSystem.cs +++ b/Content.Server/Mobs/CritMobActionsSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Chat.Systems; using Content.Server.Popups; using Content.Server.Speech.Muting; +using Content.Shared.Chat; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SpeakOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SpeakOperator.cs index cf07831959b..7163af5f651 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SpeakOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SpeakOperator.cs @@ -1,4 +1,5 @@ using Content.Server.Chat.Systems; +using Content.Shared.Chat; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs index 01cfbd113d9..467da4739b7 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs @@ -1,6 +1,7 @@ using Content.Server.Chat.Systems; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.NPC.Components; +using Content.Shared.Chat; using Content.Shared.Damage; using Content.Shared.Emag.Components; using Content.Shared.Interaction; diff --git a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs b/Content.Server/Nyanotrasen/Chat/TSayCommand.cs index 9ba27b65d71..cae234a9934 100644 --- a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs +++ b/Content.Server/Nyanotrasen/Chat/TSayCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Content.Shared.Chat; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; diff --git a/Content.Server/Nyanotrasen/Mail/MailSystem.cs b/Content.Server/Nyanotrasen/Mail/MailSystem.cs index ac73388d6c7..05cd0c88a72 100644 --- a/Content.Server/Nyanotrasen/Mail/MailSystem.cs +++ b/Content.Server/Nyanotrasen/Mail/MailSystem.cs @@ -29,6 +29,7 @@ using Content.Shared.Access; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; +using Content.Shared.Chat; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Emag.Components; diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index bc3c22cc350..d29a191f88a 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -3,6 +3,7 @@ using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; using Content.Server.StationEvents.Events; +using Content.Shared.Chat; using Content.Shared.Interaction; using Content.Shared.Psionics.Glimmer; using Content.Shared.Radio; diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index bfdd49213ee..7232a23d2c8 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -85,6 +85,9 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann if (language == null) language = _language.GetLanguage(messageSource); + if (!language.SpeechOverride.AllowRadio) + return; + // TODO if radios ever garble / modify messages, feedback-prevention needs to be handled better than this. if (!_messages.Add(message)) return; @@ -176,11 +179,14 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann private string WrapRadioMessage(EntityUid source, RadioChannelPrototype channel, string name, string message, LanguagePrototype language) { var speech = _chat.GetSpeechVerb(source, message); + // TODO this is done just to preserve the old look of radio, perhaps we can change it as well? + var languageColor = language.SpeechOverride.Color == Color.White ? channel.Color : language.SpeechOverride.Color; + return Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", ("color", channel.Color), - ("languageColor", language.Color ?? channel.Color), - ("fontType", language.FontId ?? speech.FontId), - ("fontSize", language.FontSize ?? speech.FontSize), + ("languageColor", languageColor), + ("fontType", language.SpeechOverride.FontId ?? speech.FontId), + ("fontSize", language.SpeechOverride.FontSize ?? speech.FontSize), ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), ("channel", $"\\[{channel.LocalizedName}\\]"), ("name", name), diff --git a/Content.Server/RatKing/RatKingSystem.cs b/Content.Server/RatKing/RatKingSystem.cs index 4b82dba3359..c52b596bcc5 100644 --- a/Content.Server/RatKing/RatKingSystem.cs +++ b/Content.Server/RatKing/RatKingSystem.cs @@ -6,6 +6,7 @@ using Content.Server.NPC.Systems; using Content.Server.Popups; using Content.Shared.Atmos; +using Content.Shared.Chat; using Content.Shared.Dataset; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; diff --git a/Content.Server/Speech/Muting/MutingSystem.cs b/Content.Server/Speech/Muting/MutingSystem.cs index 238d501e249..fc3349a9387 100644 --- a/Content.Server/Speech/Muting/MutingSystem.cs +++ b/Content.Server/Speech/Muting/MutingSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Abilities.Mime; using Content.Server.Chat.Systems; +using Content.Server.Language; using Content.Server.Popups; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; @@ -12,7 +13,9 @@ namespace Content.Server.Speech.Muting { public sealed class MutingSystem : EntitySystem { + [Dependency] private readonly LanguageSystem _languages = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; + public override void Initialize() { base.Initialize(); @@ -47,7 +50,9 @@ private void OnScreamAction(EntityUid uid, MutedComponent component, ScreamActio private void OnSpeakAttempt(EntityUid uid, MutedComponent component, SpeakAttemptEvent args) { - // TODO something better than this. + var language = _languages.GetLanguage(uid); + if (!language.SpeechOverride.RequireSpeech) + return; // Cannot mute if there's no speech involved if (HasComp(uid)) _popupSystem.PopupEntity(Loc.GetString("mime-cant-speak"), uid, uid); diff --git a/Content.Server/Speech/Systems/RandomBarkSystem.cs b/Content.Server/Speech/Systems/RandomBarkSystem.cs index 4fc9dd420d2..863ea798433 100644 --- a/Content.Server/Speech/Systems/RandomBarkSystem.cs +++ b/Content.Server/Speech/Systems/RandomBarkSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Mind.Components; using Robust.Shared.Random; using Content.Server.Speech.Components; +using Content.Shared.Chat; namespace Content.Server.Speech.Systems; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs index 0e694a801eb..206c0800f0a 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; using Content.Server.Speech; +using Content.Shared.Chat; using Content.Shared.Speech; using Robust.Shared.Audio.Systems; using Robust.Shared.Timing; diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index 82249bb0ccb..22840cde8f5 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -24,6 +24,7 @@ using Robust.Shared.Random; using System.Linq; using System.Numerics; +using Content.Shared.Chat; namespace Content.Server.Weapons.Melee; diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs index 8d14adcc24b..c48d70405f2 100644 --- a/Content.Shared/Chat/SharedChatSystem.cs +++ b/Content.Shared/Chat/SharedChatSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Radio; using Content.Shared.Speech; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Chat; @@ -21,7 +22,7 @@ public abstract class SharedChatSystem : EntitySystem public const char EmotesAltPrefix = '*'; 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] @@ -243,3 +244,42 @@ public static string GetStringInsideTag(ChatMessage message, string tag) return rawmsg.Substring(tagStart, tagEnd - tagStart); } } + +/// +/// InGame IC chat is for chat that is specifically ingame (not lobby) but is also in character, i.e. speaking. +/// +// ReSharper disable once InconsistentNaming +[Serializable, NetSerializable] +public enum InGameICChatType : byte +{ + Speak, + Emote, + Whisper, + Telepathic +} + +/// +/// InGame OOC chat is for chat that is specifically ingame (not lobby) but is OOC, like deadchat or LOOC. +/// +[Serializable, NetSerializable] +public enum InGameOOCChatType : byte +{ + Looc, + Dead +} + +/// +/// Controls transmission of chat. +/// +[Serializable, NetSerializable] +public enum ChatTransmitRange : byte +{ + /// Acts normal, ghosts can hear across the map, etc. + Normal, + /// Normal but ghosts are still range-limited. + GhostRangeLimit, + /// Hidden from the chat window. + HideChat, + /// Ghosts can't hear or see it at all. Regular players can if in-range. + NoGhosts +} diff --git a/Content.Shared/Language/LanguagePrototype.cs b/Content.Shared/Language/LanguagePrototype.cs index 79c17daccd8..d3a977202be 100644 --- a/Content.Shared/Language/LanguagePrototype.cs +++ b/Content.Shared/Language/LanguagePrototype.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chat; using Robust.Shared.Prototypes; namespace Content.Shared.Language; @@ -8,27 +9,18 @@ public sealed class LanguagePrototype : IPrototype [IdDataField] public string ID { get; private set; } = default!; - [DataField("color")] - public Color? Color; - - [DataField("fontId")] - public string? FontId; - - [DataField("fontSize")] - public int? FontSize; - - /// - /// If true, will mark the language as a SignLanguage and will be handled as such. - /// - [DataField("signLanguage")] - public bool? SignLanguage; - /// /// Obfuscation method used by this language. By default, uses /// [DataField("obfuscation")] public ObfuscationMethod Obfuscation = ObfuscationMethod.Default; + /// + /// Speech overrides used for messages sent in this language. + /// + [DataField("speech")] + public SpeechOverrideInfo SpeechOverride = new(); + #region utility /// /// The in-world name of this language, localized. @@ -41,3 +33,48 @@ public sealed class LanguagePrototype : IPrototype public string Description => Loc.GetString($"language-{ID}-description"); #endregion utility } + +[DataDefinition] +public sealed partial class SpeechOverrideInfo +{ + [DataField] + public Color Color = Color.White; + + [DataField] + public string? FontId; + + [DataField] + public int? FontSize; + + [DataField] + public bool AllowRadio = true; + + /// + /// If false, the entity can use this language even when it's unable to speak (i.e. muffled or muted), + /// and accents are not applied to messages in this language. + /// + [DataField] + public bool RequireSpeech = true; + + /// + /// If not null, all messages in this language will be forced to be spoken in this chat type. + /// + [DataField] + public InGameICChatType? ChatTypeOverride; + + /// + /// Speech verb overrides. If not provided, the default ones for the entity are used. + /// + [DataField] + public List? SpeechVerbOverrides; + + /// + /// Overrides for different kinds chat message wraps. If not provided, the default ones are used. + /// + /// + /// Currently, only local chat and whispers support this. Radio and emotes are unaffected. + /// This is horrible. + /// + [DataField] + public Dictionary MessageWrapOverrides = new(); +} diff --git a/Resources/Locale/en-US/language/languages-sign.ftl b/Resources/Locale/en-US/language/languages-sign.ftl new file mode 100644 index 00000000000..a431a0637f4 --- /dev/null +++ b/Resources/Locale/en-US/language/languages-sign.ftl @@ -0,0 +1,6 @@ +chat-sign-language-message-wrap = [italic][BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] [BubbleContent]{$verb} [font="{$fontType}" size={$fontSize}][color={$color}]{$message}[/color][/font][/italic][/BubbleContent] +chat-sign-language-whisper-wrap = [italic][BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] [BubbleContent]subtly gestures [font="{$fontType}" size={$fontSize}][color={$color}]{$message}[/color][/font][/italic][/BubbleContent] + +chat-speech-verb-sign-1 = gestures +chat-speech-verb-sign-2 = signs +chat-speech-verb-sign-3 = waves diff --git a/Resources/Locale/en-US/language/languages.ftl b/Resources/Locale/en-US/language/languages.ftl index 209daf92de8..56dbe04f462 100644 --- a/Resources/Locale/en-US/language/languages.ftl +++ b/Resources/Locale/en-US/language/languages.ftl @@ -4,9 +4,6 @@ language-Universal-description = What are you? language-GalacticCommon-name = Galactic common language-GalacticCommon-description = The standard Galatic language, most commonly used for inter-species communications and legal work. -language-SignLanguage-name = Sign Language -language-SignLanguage-description = The standard Galactic sign language, used by those that are unable to speak Galactic Common or at all. - language-Bubblish-name = Bubblish language-Bubblish-description = The language of Slimes. Being a mixture of bubbling noises and pops it's very difficult to speak for humans without the use of mechanical aids. @@ -72,3 +69,6 @@ language-Crab-description = Click! language-Kobold-name = Kobold language-Kobold-description = Hiss! + +language-Sign-name = Sign Language +language-Sign-description = The standard Galactic sign language, used by those that are unable to speak Galactic Common or at all. diff --git a/Resources/Locale/en-US/language/sign-language.ftl b/Resources/Locale/en-US/language/sign-language.ftl deleted file mode 100644 index f4548f995c5..00000000000 --- a/Resources/Locale/en-US/language/sign-language.ftl +++ /dev/null @@ -1,4 +0,0 @@ -entity-signlanguage-message = [italic]{$entityName} signs "[BubbleContent]{$message}[/BubbleContent]"[/italic] - -language-signlanguage-1 = [italic]{$entityName} signs something.[/italic] -language-signlanguage-2 = [italic]{$entityName} makes weird hand gestures.[/italic] diff --git a/Resources/Prototypes/Language/languages.yml b/Resources/Prototypes/Language/languages.yml index bec1884fe5c..566ee082914 100644 --- a/Resources/Prototypes/Language/languages.yml +++ b/Resources/Prototypes/Language/languages.yml @@ -35,20 +35,12 @@ - nah - wah -- type: language - id: SignLanguage - signLanguage: true - obfuscation: - !type:ReplacementObfuscation - replacement: - - "language-signlanguage-1" - - "language-signlanguage-2" - # Spoken by slimes. - type: language id: Bubblish - color: "#0077aa" - fontId: RubikBubbles + speech: + color: "#0077aa" + fontId: RubikBubbles obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -63,8 +55,9 @@ # Spoken by moths. - type: language id: Moffic - color: "#869b29" - fontId: Copperplate + speech: + color: "#869b29" + fontId: Copperplate obfuscation: !type:SyllableObfuscation minSyllables: 2 # Replacements are really short @@ -131,8 +124,9 @@ # Spoken by dionas. - type: language id: RootSpeak - color: "#804000" - fontId: Noganas + speech: + color: "#804000" + fontId: Noganas obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -147,8 +141,9 @@ # A mess of broken Japanese, spoken by Felinds and Oni - type: language id: Nekomimetic - color: "#803B56" - fontId: Manga + speech: + color: "#803B56" + fontId: Manga obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -206,7 +201,8 @@ # Spoken by the Lizard race. - type: language id: Draconic - color: "#228b22" + speech: + color: "#228b22" obfuscation: !type:SyllableObfuscation minSyllables: 2 @@ -300,7 +296,8 @@ # Spoken by the Vulpkanin race. - type: language id: Canilunzt - color: "#b97a57" + speech: + color: "#b97a57" obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -367,7 +364,8 @@ # The common language of the Sol system. - type: language id: SolCommon - color: "#8282fb" + speech: + color: "#8282fb" obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -393,7 +391,8 @@ - type: language id: RobotTalk - fontId: Monospace + speech: + fontId: Monospace obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -576,3 +575,28 @@ - hiss - ss - ee + +# Example of a sign language. Not currently used anyhow. +- type: language + id: Sign + speech: + allowRadio: false + requireSpeech: false + color: "#dddddd" + messageWrapOverrides: + Speak: chat-sign-language-message-wrap + Whisper: chat-sign-language-whisper-wrap + speechVerbOverrides: + - chat-speech-verb-sign-1 + - chat-speech-verb-sign-2 + - chat-speech-verb-sign-3 + obfuscation: + !type:ReplacementObfuscation + replacement: + - something + - a cryptic message to you + - a signal to you + - a message + - a rude expression to you + - a sad expression to you + - a happy expression to you