From 6e648aceaa4c09502649ab4b4247f6e0462b6128 Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Fri, 2 Aug 2024 06:37:07 +0400 Subject: [PATCH 01/15] =?UTF-8?q?=D0=A2=D0=BE=D1=82=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D1=80=D0=B5=D0=B2=D0=BE=D1=80=D0=BA=20?= =?UTF-8?q?=D1=8F=D0=B7=D1=8B=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/Language/LanguageMenuUIController.cs | 51 --- Content.Client/ADT/Language/LanguageSystem.cs | 5 + .../ADT/Language/Systems/LanguageSystem.cs | 8 - .../Systems/TranslatorImplanterSystem.cs | 8 - .../ADT/Language/TranslatorImplantSystem.cs | 8 + .../Language/{ => UI}/LanguageMenuWindow.xaml | 4 +- .../{ => UI}/LanguageMenuWindow.xaml.cs | 59 ++- Content.Client/Corvax/TTS/TTSSystem.cs | 18 +- Content.Client/Input/ContentContexts.cs | 1 + .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 1 + .../Languages/LanguageMenuUIController.cs | 120 ++++++ .../MenuBar/GameTopMenuBarUIController.cs | 4 + .../MenuBar/Widgets/GameTopMenuBar.xaml | 12 +- .../Language/Commands/ListLanguagesCommand.cs | 39 -- .../Language/Commands/SayLanguageCommand.cs | 53 --- .../Commands/SelectLanguageCommand.cs | 48 --- .../ADT/Language/LanguageSystem.Windows.cs | 40 -- Content.Server/ADT/Language/LanguageSystem.cs | 258 +++--------- .../ADT/Language/TranslatorImplantSystem.cs | 8 + .../ADT/Language/TranslatorImplanterSystem.cs | 79 ---- .../ADT/Language/TranslatorSystem.cs | 208 +--------- Content.Server/Chat/Systems/ChatSystem.cs | 288 +++++++------ Content.Server/Corvax/TTS/TTSSystem.cs | 35 +- .../EntityEffects/Effects/MakeSentient.cs | 14 + .../Mind/Commands/MakeSentientCommand.cs | 13 + .../Radio/EntitySystems/HeadsetSystem.cs | 9 +- .../Radio/EntitySystems/RadioDeviceSystem.cs | 4 +- .../Radio/EntitySystems/RadioSystem.cs | 43 +- Content.Server/Radio/RadioEvent.cs | 3 +- .../Language/Components/CommonLangUnknown.cs | 14 - .../Components/HandheldTranslatorComponent.cs | 27 ++ .../Components/LanguageSpeakerComponent.cs | 49 +-- .../Components/TranslatorComponent.cs | 93 ----- .../Components/TranslatorImplantComponent.cs | 42 ++ .../TranslatorImplanterComponent.cs | 34 -- .../UniversalLanguageSpeacerComponent.cs | 11 - .../ADT/Language/LanguagePrototype.cs | 23 +- .../Language/Systems/SharedLanguageSystem.cs | 271 ++++++++++-- .../Systems/SharedTranslatorImplantSystem.cs | 113 +++++ .../SharedTranslatorImplanterSystem.cs | 36 -- .../Systems/SharedTranslatorSystem.cs | 5 +- Content.Shared/Corvax/TTS/PlayTTSEvent.cs | 10 +- Content.Shared/Input/ContentKeyFunctions.cs | 1 + Content.Shared/Radio/RadioChannelPrototype.cs | 7 +- .../Locale/ru-RU/ADT/Languages/languages.ftl | 48 +-- .../ADT/prototypes/Actions/language-menu.ftl | 6 +- .../Entities/Objects/Device/translators.ftl | 10 + .../Entities/Objects/Misc/implanters.ftl | 11 +- Resources/Prototypes/ADT/Actions/language.yml | 12 - .../Objects/Device/Translators/handheld.yml | 341 +++++++++++++++ .../Objects/Device/Translators/implanters.yml | 167 ++++++++ .../Objects/Device/Translators/implants.yml | 297 ++++++++++++++ .../Entities/Objects/Device/translators.yml | 388 ------------------ .../ADT/Entities/Objects/Misc/implanters.yml | 287 ------------- .../Prototypes/ADT/Languages/languages.yml | 45 +- .../ADT/Recipes/Lathes/translators.yml | 83 ++-- .../Prototypes/ADT/Research/translators.yml | 16 +- .../Entities/Mobs/Player/observer.yml | 6 +- .../Entities/Structures/Machines/lathe.yml | 15 +- .../Objects/Devices/translator.rsi/icon.png | Bin .../translator.rsi/inhand-left-translator.png | Bin .../Devices/translator.rsi/inhand-left.png | Bin .../inhand-right-translator.png | Bin .../Devices/translator.rsi/inhand-right.png | Bin .../Objects/Devices/translator.rsi/meta.json | 0 .../Devices/translator.rsi/translator.png | Bin .../Textures/Interface/languages-menu.svg | 7 + .../Interface/languages-menu.svg.192dpi.png | Bin 0 -> 804 bytes .../languages-menu.svg.192dpi.png.yml | 2 + Resources/keybinds.yml | 5 +- 70 files changed, 1953 insertions(+), 1970 deletions(-) delete mode 100644 Content.Client/ADT/Language/LanguageMenuUIController.cs create mode 100644 Content.Client/ADT/Language/LanguageSystem.cs delete mode 100644 Content.Client/ADT/Language/Systems/LanguageSystem.cs delete mode 100644 Content.Client/ADT/Language/Systems/TranslatorImplanterSystem.cs create mode 100644 Content.Client/ADT/Language/TranslatorImplantSystem.cs rename Content.Client/ADT/Language/{ => UI}/LanguageMenuWindow.xaml (91%) rename Content.Client/ADT/Language/{ => UI}/LanguageMenuWindow.xaml.cs (59%) create mode 100644 Content.Client/UserInterface/Systems/Languages/LanguageMenuUIController.cs delete mode 100644 Content.Server/ADT/Language/Commands/ListLanguagesCommand.cs delete mode 100644 Content.Server/ADT/Language/Commands/SayLanguageCommand.cs delete mode 100644 Content.Server/ADT/Language/Commands/SelectLanguageCommand.cs delete mode 100644 Content.Server/ADT/Language/LanguageSystem.Windows.cs create mode 100644 Content.Server/ADT/Language/TranslatorImplantSystem.cs delete mode 100644 Content.Server/ADT/Language/TranslatorImplanterSystem.cs delete mode 100644 Content.Shared/ADT/Language/Components/CommonLangUnknown.cs create mode 100644 Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs delete mode 100644 Content.Shared/ADT/Language/Components/TranslatorComponent.cs create mode 100644 Content.Shared/ADT/Language/Components/TranslatorImplantComponent.cs delete mode 100644 Content.Shared/ADT/Language/Components/TranslatorImplanterComponent.cs delete mode 100644 Content.Shared/ADT/Language/Components/UniversalLanguageSpeacerComponent.cs create mode 100644 Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs delete mode 100644 Content.Shared/ADT/Language/Systems/SharedTranslatorImplanterSystem.cs delete mode 100644 Resources/Prototypes/ADT/Actions/language.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml delete mode 100644 Resources/Prototypes/ADT/Entities/Objects/Device/translators.yml delete mode 100644 Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/icon.png (100%) rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/inhand-left-translator.png (100%) rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/inhand-left.png (100%) rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/inhand-right-translator.png (100%) rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/inhand-right.png (100%) rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/meta.json (100%) rename Resources/Textures/{_NF => ADT}/Objects/Devices/translator.rsi/translator.png (100%) create mode 100644 Resources/Textures/Interface/languages-menu.svg create mode 100644 Resources/Textures/Interface/languages-menu.svg.192dpi.png create mode 100644 Resources/Textures/Interface/languages-menu.svg.192dpi.png.yml diff --git a/Content.Client/ADT/Language/LanguageMenuUIController.cs b/Content.Client/ADT/Language/LanguageMenuUIController.cs deleted file mode 100644 index 791b616bb3d..00000000000 --- a/Content.Client/ADT/Language/LanguageMenuUIController.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Content.Client.ADT.Language; -using Content.Client.Gameplay; -using Content.Shared.Language; -using Robust.Client.UserInterface.Controllers; -using Robust.Client.UserInterface.Controls; -using static Content.Shared.Language.Systems.SharedLanguageSystem; - -namespace Content.Client.ADT.Language; - -public sealed class LanguageMenuUIController : UIController, IOnStateEntered, IOnStateExited -{ - public LanguageMenuWindow? _languageWindow; - - public override void Initialize() - { - EntityManager.EventBus.SubscribeLocalEvent(OnActionMenu); - EntityManager.EventBus.SubscribeEvent(EventSource.Network, this, OnStateUpdate); - } - - private void OnStateUpdate(LanguageMenuStateMessage ev) - { - if (_languageWindow == null) - return; - - _languageWindow.UpdateState(ev); - } - - private void OnActionMenu(EntityUid uid, LanguageSpeakerComponent component, LanguageMenuActionEvent args) - { - if (_languageWindow == null) - return; - - if (!_languageWindow.IsOpen) - { - _languageWindow.Open(); - EntityManager.EntityNetManager?.SendSystemNetworkMessage(new RequestLanguageMenuStateMessage()); - } - } - - public void OnStateEntered(GameplayState state) - { - _languageWindow = UIManager.CreateWindow(); - LayoutContainer.SetAnchorPreset(_languageWindow, LayoutContainer.LayoutPreset.Center); - } - - public void OnStateExited(GameplayState state) - { - _languageWindow?.Dispose(); - _languageWindow = null; - } -} diff --git a/Content.Client/ADT/Language/LanguageSystem.cs b/Content.Client/ADT/Language/LanguageSystem.cs new file mode 100644 index 00000000000..8312272ffc1 --- /dev/null +++ b/Content.Client/ADT/Language/LanguageSystem.cs @@ -0,0 +1,5 @@ +namespace Content.Shared.Language; + +public sealed partial class LanguageSystem : SharedLanguageSystem +{ +} diff --git a/Content.Client/ADT/Language/Systems/LanguageSystem.cs b/Content.Client/ADT/Language/Systems/LanguageSystem.cs deleted file mode 100644 index 4d603a700a9..00000000000 --- a/Content.Client/ADT/Language/Systems/LanguageSystem.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Content.Shared.Language.Systems; - -namespace Content.Client.Language.Systems; - -public sealed class LanguageSystem : SharedLanguageSystem -{ - -} diff --git a/Content.Client/ADT/Language/Systems/TranslatorImplanterSystem.cs b/Content.Client/ADT/Language/Systems/TranslatorImplanterSystem.cs deleted file mode 100644 index bbe28d24f5d..00000000000 --- a/Content.Client/ADT/Language/Systems/TranslatorImplanterSystem.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Content.Shared.Language.Systems; - -namespace Content.Client.Language.Systems; - -public sealed class TranslatorImplanterSystem : SharedTranslatorImplanterSystem -{ - -} diff --git a/Content.Client/ADT/Language/TranslatorImplantSystem.cs b/Content.Client/ADT/Language/TranslatorImplantSystem.cs new file mode 100644 index 00000000000..d34d770997e --- /dev/null +++ b/Content.Client/ADT/Language/TranslatorImplantSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Implants; + +namespace Content.Client.Implants; + +public sealed class TranslatorImplantSystem : SharedTranslatorImplantSystem +{ + +} diff --git a/Content.Client/ADT/Language/LanguageMenuWindow.xaml b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml similarity index 91% rename from Content.Client/ADT/Language/LanguageMenuWindow.xaml rename to Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml index 188b3bc3b54..cfc61b2792f 100644 --- a/Content.Client/ADT/Language/LanguageMenuWindow.xaml +++ b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml @@ -1,7 +1,7 @@ - + SetSize="400 450"> diff --git a/Content.Client/ADT/Language/LanguageMenuWindow.xaml.cs b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs similarity index 59% rename from Content.Client/ADT/Language/LanguageMenuWindow.xaml.cs rename to Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs index 0a795aebbd1..8492e15de40 100644 --- a/Content.Client/ADT/Language/LanguageMenuWindow.xaml.cs +++ b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs @@ -1,21 +1,24 @@ -using Content.Client.Language.Systems; using Content.Shared.Language; -using Content.Shared.Language.Systems; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Console; using Robust.Shared.Utility; -using static Content.Shared.Language.Systems.SharedLanguageSystem; +using Robust.Shared.Player; -namespace Content.Client.ADT.Language; // This EXACT class must have the _NF part because of xaml linking +namespace Content.Client.ADT.Language.UI; [GenerateTypedNameReferences] public sealed partial class LanguageMenuWindow : DefaultWindow { [Dependency] private readonly IConsoleHost _consoleHost = default!; - private readonly LanguageSystem _language; + [Dependency] private readonly EntityManager _entManager = default!; + [Dependency] private readonly IEntityManager _iEntManager = default!; + + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + + private readonly SharedLanguageSystem _language; private readonly List _entries = new(); @@ -26,12 +29,19 @@ public LanguageMenuWindow() _language = IoCManager.Resolve().GetEntitySystem(); Title = Loc.GetString("language-menu-window-title"); + + var player = _playerManager.LocalSession?.AttachedEntity; + + if (_entManager.TryGetComponent(player, out var lang) && lang.CurrentLanguage != null) + { + var ev = new LanguageMenuStateMessage(_entManager.GetNetEntity(player.Value), lang.CurrentLanguage, lang.UnderstoodLanguages); + UpdateState(ev); + } } public void UpdateState(LanguageMenuStateMessage state) { - var clanguage = _language.GetLanguage(state.CurrentLanguage); - CurrentLanguageLabel.Text = Loc.GetString("language-menu-current-language", ("language", clanguage?.LocalizedName ?? "")); + CurrentLanguageLabel.Text = Loc.GetString("language-menu-current-language", ("language", _language.GetLanguage(state.CurrentLanguage).LocalizedName)); OptionsList.RemoveAllChildren(); _entries.Clear(); @@ -44,16 +54,21 @@ public void UpdateState(LanguageMenuStateMessage state) // Disable the button for the currently chosen language foreach (var entry in _entries) { - if (entry.button != null) - entry.button.Disabled = entry.language == state.CurrentLanguage; + if (entry.Button != null) + { + entry.Button.Disabled = entry.Language == state.CurrentLanguage || !_language.CanSpeak(_entManager.GetEntity(state.ComponentOwner), _language.GetLanguage(entry.Language)); + if (entry.Language == state.CurrentLanguage) + entry.Button.Text = Loc.GetString("language-choose-button-chosen"); + if (!_language.CanSpeak(_entManager.GetEntity(state.ComponentOwner), _language.GetLanguage(entry.Language))) + entry.Button.Text = Loc.GetString("language-choose-button-cannot"); + } } } private void AddLanguageEntry(string language) { - var proto = _language.GetLanguage(language); - var state = new EntryState { language = language }; - + var state = new EntryState { Language = language }; + var prototype = _language.GetLanguage(language); var container = new BoxContainer(); container.Orientation = BoxContainer.LayoutOrientation.Vertical; @@ -67,14 +82,16 @@ private void AddLanguageEntry(string language) header.SeparationOverride = 2; var name = new Label(); - name.Text = proto?.LocalizedName ?? ""; + name.Text = prototype.LocalizedName; + if (prototype.Color != null) + name.FontColorOverride = prototype.Color.Value; name.MinWidth = 50; name.HorizontalExpand = true; var button = new Button(); - button.Text = "Выбрать"; + button.Text = Loc.GetString("language-choose-button"); button.OnPressed += _ => OnLanguageChosen(language); - state.button = button; + state.Button = button; header.AddChild(name); header.AddChild(button); @@ -89,7 +106,7 @@ private void AddLanguageEntry(string language) body.Margin = new Thickness(4f, 4f); var description = new RichTextLabel(); - description.SetMessage(proto?.LocalizedDescription ?? ""); + description.SetMessage(prototype.LocalizedDescription); description.HorizontalExpand = true; body.AddChild(description); @@ -113,12 +130,16 @@ private void AddLanguageEntry(string language) private void OnLanguageChosen(string id) { - _consoleHost.ExecuteCommand("lsselectlang " + id); + var player = _entManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity); + if (player == null) + return; + + _language.SelectLanguage(player.Value, id); } private struct EntryState { - public string language; - public Button? button; + public string Language; + public Button? Button; } } diff --git a/Content.Client/Corvax/TTS/TTSSystem.cs b/Content.Client/Corvax/TTS/TTSSystem.cs index b31ba16d621..dc65f907b22 100644 --- a/Content.Client/Corvax/TTS/TTSSystem.cs +++ b/Content.Client/Corvax/TTS/TTSSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Chat; +using Content.Shared.Chat; using Content.Shared.Corvax.CCCVars; using Content.Shared.Corvax.TTS; using Robust.Client.Audio; @@ -8,6 +8,8 @@ using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.Utility; +using Content.Shared.Language; +using Robust.Shared.Player; namespace Content.Client.Corvax.TTS; @@ -20,6 +22,8 @@ public sealed class TTSSystem : EntitySystem [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IResourceManager _res = default!; [Dependency] private readonly AudioSystem _audio = default!; + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + [Dependency] private readonly SharedLanguageSystem _language = default!; private ISawmill _sawmill = default!; private readonly MemoryContentRoot _contentRoot = new(); @@ -68,7 +72,17 @@ private void OnPlayTTS(PlayTTSEvent ev) _sawmill.Verbose($"Play TTS audio {ev.Data.Length} bytes from {ev.SourceUid} entity"); var filePath = new ResPath($"{_fileIdx++}.ogg"); - _contentRoot.AddOrUpdateFile(filePath, ev.Data); + + var player = _playerManager.LocalSession?.AttachedEntity; + if (player != null) + { + if (_language.CanUnderstand(player.Value, ev.LanguageProtoId)) + _contentRoot.AddOrUpdateFile(filePath, ev.Data); + else + _contentRoot.AddOrUpdateFile(filePath, ev.LanguageData); + } + else + _contentRoot.AddOrUpdateFile(filePath, ev.Data); var audioResource = new AudioResource(); audioResource.Load(IoCManager.Instance!, Prefix / filePath); diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 7a8a9938545..d0dbace0b15 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -61,6 +61,7 @@ public static void SetupContexts(IInputContextContainer contexts) human.AddFunction(ContentKeyFunctions.AltUseItemInHand); human.AddFunction(ContentKeyFunctions.OpenCharacterMenu); human.AddFunction(ContentKeyFunctions.OpenEmotesMenu); + human.AddFunction(ContentKeyFunctions.OpenLanguagesMenu); human.AddFunction(ContentKeyFunctions.ActivateItemInWorld); human.AddFunction(ContentKeyFunctions.ThrowItemInHand); human.AddFunction(ContentKeyFunctions.AltActivateItemInWorld); diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index 6fa416ed59c..af22be091a0 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -216,6 +216,7 @@ void AddCheckBox(string checkBoxName, bool currentState, Action, IOnStateExited +{ + public LanguageMenuWindow? _menu; + private MenuButton? LanguagesButton => UIManager.GetActiveUIWidgetOrNull()?.LanguagesButton; + + public override void Initialize() + { + + EntityManager.EventBus.SubscribeEvent(EventSource.All, this, OnStateUpdate); + } + + private void OnStateUpdate(LanguageMenuStateMessage ev) + { + if (_menu == null) + return; + + _menu.UpdateState(ev); + } + + + public void OnStateEntered(GameplayState state) + { + CommandBinds.Builder + .Bind(ContentKeyFunctions.OpenLanguagesMenu, + InputCmdHandler.FromDelegate(_ => ToggleLanguagesMenu())) + .Register(); + } + + public void OnStateExited(GameplayState state) + { + CommandBinds.Unregister(); + } + + private void ToggleLanguagesMenu() + { + if (_menu == null) + { + // setup window + _menu = UIManager.CreateWindow(); + _menu.OnClose += OnWindowClosed; + _menu.OnOpen += OnWindowOpen; + //_menu.OnPlayEmote += OnPlayEmote; + + if (LanguagesButton != null) + LanguagesButton.SetClickPressed(true); + + _menu.OpenCentered(); + } + else + { + _menu.OnClose -= OnWindowClosed; + _menu.OnOpen -= OnWindowOpen; + //_menu.OnPlayEmote -= OnPlayEmote; + + if (LanguagesButton != null) + LanguagesButton.SetClickPressed(false); + + CloseMenu(); + } + } + + public void UnloadButton() + { + if (LanguagesButton == null) + return; + + LanguagesButton.OnPressed -= ActionButtonPressed; + } + + public void LoadButton() + { + if (LanguagesButton == null) + return; + + LanguagesButton.OnPressed += ActionButtonPressed; + } + + private void ActionButtonPressed(BaseButton.ButtonEventArgs args) + { + ToggleLanguagesMenu(); + } + + private void OnWindowClosed() + { + if (LanguagesButton != null) + LanguagesButton.Pressed = false; + + CloseMenu(); + } + + private void OnWindowOpen() + { + if (LanguagesButton != null) + LanguagesButton.Pressed = true; + } + + private void CloseMenu() + { + if (_menu == null) + return; + + _menu.Dispose(); + _menu = null; + } +} diff --git a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs index e314310bc0c..0b29310f71d 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs +++ b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs @@ -9,6 +9,7 @@ using Content.Client.UserInterface.Systems.Guidebook; using Content.Client.UserInterface.Systems.MenuBar.Widgets; using Content.Client.UserInterface.Systems.Sandbox; +using Content.Client.UserInterface.Systems.Language; // Lang affected using Robust.Client.UserInterface.Controllers; namespace Content.Client.UserInterface.Systems.MenuBar; @@ -24,6 +25,7 @@ public sealed class GameTopMenuBarUIController : UIController [Dependency] private readonly SandboxUIController _sandbox = default!; [Dependency] private readonly GuidebookUIController _guidebook = default!; [Dependency] private readonly EmotesUIController _emotes = default!; + [Dependency] private readonly LanguageMenuUIController _language = default!; // Lang affected private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull(); @@ -47,6 +49,7 @@ public void UnloadButtons() _action.UnloadButton(); _sandbox.UnloadButton(); _emotes.UnloadButton(); + _language.UnloadButton(); // Lang affected } public void LoadButtons() @@ -60,5 +63,6 @@ public void LoadButtons() _action.LoadButton(); _sandbox.LoadButton(); _emotes.LoadButton(); + _language.LoadButton(); // Lang affected } } diff --git a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml index dc8972970ac..751a223bdf3 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml +++ b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml @@ -1,4 +1,4 @@ - + "lslangs"; - public string Description => "List languages your current entity can speak at the current moment."; - public string Help => "lslangs"; - - 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; - } - - var languages = IoCManager.Resolve().GetEntitySystem(); - - var (spokenLangs, knownLangs) = languages.GetAllLanguages(playerEntity); - - shell.WriteLine("Spoken: " + string.Join(", ", spokenLangs)); - shell.WriteLine("Understood: " + string.Join(", ", knownLangs)); - } -} diff --git a/Content.Server/ADT/Language/Commands/SayLanguageCommand.cs b/Content.Server/ADT/Language/Commands/SayLanguageCommand.cs deleted file mode 100644 index 711c2c5fbfb..00000000000 --- a/Content.Server/ADT/Language/Commands/SayLanguageCommand.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Content.Server.Chat.Systems; -using Content.Shared.Administration; -using Robust.Shared.Console; -using Robust.Shared.Enums; - -namespace Content.Server.Language.Commands; - -[AnyCommand] -public sealed class SayLanguageCommand : IConsoleCommand -{ - public string Command => "lsay"; - public string Description => "Send chat languages to the local channel or a specific chat channel, in a specific language."; - public string Help => "lsay "; - - 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 < 2) - return; - - var languageId = args[0]; - var message = string.Join(" ", args, startIndex: 1, count: args.Length - 1).Trim(); - - if (string.IsNullOrEmpty(message)) - return; - - var languages = IoCManager.Resolve().GetEntitySystem(); - var chats = IoCManager.Resolve().GetEntitySystem(); - - var language = languages.GetLanguage(languageId); - if (language == null || !languages.CanSpeak(playerEntity, language.ID)) - { - shell.WriteError($"Language {languageId} is invalid or you cannot speak it!"); - return; - } - - chats.TrySendInGameICMessage(playerEntity, message, InGameICChatType.Speak, ChatTransmitRange.Normal, false, shell, player, languageOverride: language); - } -} diff --git a/Content.Server/ADT/Language/Commands/SelectLanguageCommand.cs b/Content.Server/ADT/Language/Commands/SelectLanguageCommand.cs deleted file mode 100644 index 72336747fab..00000000000 --- a/Content.Server/ADT/Language/Commands/SelectLanguageCommand.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Linq; -using Content.Shared.Administration; -using Robust.Shared.Console; -using Robust.Shared.Enums; - -namespace Content.Server.Language.Commands; - -[AnyCommand] -public sealed class SelectLanguageCommand : IConsoleCommand -{ - public string Command => "lsselectlang"; - public string Description => "Open a menu to select a langauge to speak."; - public string Help => "lsselectlang"; - - 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 languageId = args[0]; - - var languages = IoCManager.Resolve().GetEntitySystem(); - - var language = languages.GetLanguage(languageId); - if (language == null || !languages.CanSpeak(playerEntity, language.ID)) - { - shell.WriteError($"Language {languageId} is invalid or you cannot speak it!"); - return; - } - - languages.SetLanguage(playerEntity, language.ID); - } -} diff --git a/Content.Server/ADT/Language/LanguageSystem.Windows.cs b/Content.Server/ADT/Language/LanguageSystem.Windows.cs deleted file mode 100644 index 52b5e7cbf46..00000000000 --- a/Content.Server/ADT/Language/LanguageSystem.Windows.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Content.Shared.Language; -using Robust.Server.GameObjects; -using Robust.Shared.Player; - -namespace Content.Server.Language; - -public sealed partial class LanguageSystem -{ - [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; - - public void InitializeWindows() - { - SubscribeNetworkEvent(OnLanguagesRequest); - SubscribeLocalEvent(OnLanguageSwitch); - } - - private void OnLanguagesRequest(RequestLanguageMenuStateMessage args, EntitySessionEventArgs session) - { - var uid = session.SenderSession.AttachedEntity; - if (uid == null) - return; - - var langs = GetLanguages(uid.Value); - if (langs == null) - return; - - var state = new LanguageMenuStateMessage(langs.CurrentLanguage, langs.SpokenLanguages); - RaiseNetworkEvent(state, uid.Value); - } - - private void OnLanguageSwitch(EntityUid uid, LanguageSpeakerComponent component, LanguagesUpdateEvent args) - { - var langs = GetLanguages(uid); - if (langs == null) - return; - - var state = new LanguageMenuStateMessage(langs.CurrentLanguage, langs.SpokenLanguages); - RaiseNetworkEvent(state, uid); - } -} diff --git a/Content.Server/ADT/Language/LanguageSystem.cs b/Content.Server/ADT/Language/LanguageSystem.cs index e76ce23cd36..1fbae6a5760 100644 --- a/Content.Server/ADT/Language/LanguageSystem.cs +++ b/Content.Server/ADT/Language/LanguageSystem.cs @@ -2,86 +2,85 @@ using System.Text; using Content.Shared.GameTicking; using Content.Shared.Language; -using Content.Shared.Language.Systems; +//using Content.Shared.Language.Systems; using Robust.Shared.Random; using Robust.Shared.Player; using Robust.Server.GameObjects; -using UniversalLanguageSpeakerComponent = Content.Shared.Language.Components.UniversalLanguageSpeakerComponent; +//using UniversalLanguageSpeakerComponent = Content.Shared.Language.Components.UniversalLanguageSpeakerComponent; +using Robust.Shared.Prototypes; +using Content.Server.Station.Systems; +using Content.Server.GameTicking.Events; +using Content.Server.Chat.Systems; namespace Content.Server.Language; public sealed partial class LanguageSystem : SharedLanguageSystem { - /// - /// A random number added to each pseudo-random number's seed. Changes every round. - /// - public int RandomRoundSeed { get; private set; } + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ChatSystem _chat = default!; + public int Seed { get; private set; } + public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInitLanguageSpeaker); - SubscribeAllEvent(it => RandomRoundSeed = _random.Next()); - SubscribeLocalEvent(OnUnknow); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnRoundStart); - InitializeWindows(); + SubscribeNetworkEvent(OnLanguageSwitch); } - private void OnInitLanguageSpeaker(EntityUid uid, LanguageSpeakerComponent component, ComponentInit args) + private void OnMapInit(EntityUid uid, LanguageSpeakerComponent component, MapInitEvent args) { - if (string.IsNullOrEmpty(component.CurrentLanguage)) - { - component.CurrentLanguage = component.SpokenLanguages.FirstOrDefault(UniversalPrototype); - } + if (component.CurrentLanguage == null) + component.CurrentLanguage = component.SpokenLanguages.FirstOrDefault("Universal"); + Dirty(uid, component); } - private void OnUnknow(EntityUid uid, UnknowLanguageComponent unknow, MapInitEvent args) + private void OnRoundStart(RoundStartingEvent args) { - TryComp(uid, out var component); + Seed = _random.Next(); + } - if (component != null) - { - component.SpokenLanguages.Remove(unknow.LanguageToForgot); - component.UnderstoodLanguages.Remove(unknow.LanguageToForgot); - component.CurrentLanguage = component.SpokenLanguages.FirstOrDefault(UniversalPrototype); - } - else + private void OnLanguageSwitch(LanguageChosenMessage args) + { + var uid = GetEntity(args.Uid); + if (!TryComp(uid, out var component) || component.CurrentLanguage == null) return; + var langs = component.UnderstoodLanguages; + if (langs == null || component.CurrentLanguage == null) + return; + + component.CurrentLanguage = args.SelectedLanguage; + + Dirty(uid, component); + + var state = new LanguageMenuStateMessage(args.Uid, component.CurrentLanguage, langs); + RaiseNetworkEvent(state, uid); } - /// - /// Obfuscate speech of the given entity, or using the given language. - /// - /// The speaker whose message needs to be obfuscated. Must not be null if "language" is not set. - /// The language for obfuscation. Must not be null if "source" is null. - public string ObfuscateSpeech(EntityUid? source, string message, LanguagePrototype? language = null) + public string ObfuscateMessage(EntityUid uid, string originalMessage, LanguagePrototype? proto = null) { - if (language == null) + if (proto == null) { - if (source is not { Valid: true }) - { - throw new NullReferenceException("Either source or language must be set."); - } - language = GetLanguage(source.Value); + proto = GetCurrentLanguage(uid); } var builder = new StringBuilder(); - if (language.ObfuscateSyllables) - { - ObfuscateSyllables(builder, message, language); - } + if (proto.ObfuscateSyllables) + ObfuscateSyllables(builder, originalMessage, proto); else - { - ObfuscatePhrases(builder, message, language); - } + ObfuscatePhrases(builder, originalMessage, proto); - //_sawmill.Info($"Got {message}, obfuscated to {builder}. Language: {language.ID}"); + var result = builder.ToString(); + result = _chat.SanitizeInGameICMessage(uid, result, out _); - return builder.ToString(); + return result; } + // OK I have no idea how to generate message so I took some voids from other PR private void ObfuscateSyllables(StringBuilder builder, string message, LanguagePrototype language) { // Go through each word. Calculate its hash sum and count the number of letters. @@ -93,7 +92,7 @@ private void ObfuscateSyllables(StringBuilder builder, string message, LanguageP { var ch = char.ToLower(message[i]); // A word ends when one of the following is found: a space, a sentence end, or EOM - if (char.IsWhiteSpace(ch) || IsSentenceEnd(ch) || i == message.Length - 1) + if (char.IsWhiteSpace(ch) || (ch is '.' or '!' or '?') || i == message.Length - 1) { var wordLength = i - wordBeginIndex; if (wordLength > 0) @@ -126,7 +125,7 @@ private void ObfuscatePhrases(StringBuilder builder, string message, LanguagePro for (var i = 0; i < message.Length; i++) { var ch = char.ToLower(message[i]); - if (IsSentenceEnd(ch) || i == message.Length - 1) + if ((ch is '.' or '!' or '?') || i == message.Length - 1) { var length = i - sentenceBeginIndex; if (length > 0) @@ -141,179 +140,18 @@ private void ObfuscatePhrases(StringBuilder builder, string message, LanguagePro } sentenceBeginIndex = i + 1; - if (IsSentenceEnd(ch)) + if ((ch is '.' or '!' or '?')) builder.Append(ch).Append(" "); } } } - public bool CanUnderstand(EntityUid listener, - LanguagePrototype language, - LanguageSpeakerComponent? listenerLanguageComp = null) - { - if (language.ID == UniversalPrototype || HasComp(listener)) - return true; - - var listenerLanguages = GetLanguages(listener, listenerLanguageComp)?.UnderstoodLanguages; - - return listenerLanguages?.Contains(language.ID, StringComparer.Ordinal) ?? false; - } - - public bool CanSpeak(EntityUid speaker, string language, LanguageSpeakerComponent? speakerComp = null) - { - if (HasComp(speaker)) - return true; - - var langs = GetLanguages(speaker, speakerComp)?.UnderstoodLanguages; - return langs?.Contains(language, StringComparer.Ordinal) ?? false; - } - - // - // Returns the current language of the given entity. Assumes Universal if not specified. - // - public LanguagePrototype GetLanguage(EntityUid speaker, LanguageSpeakerComponent? languageComp = null) - { - var id = GetLanguages(speaker, languageComp)?.CurrentLanguage; - if (id == null) - return Universal; // Fallback - - _prototype.TryIndex(id, out LanguagePrototype? proto); - - return proto ?? Universal; - } - - // - // Set the CurrentLanguage of the given entity. - // - public void SetLanguage(EntityUid speaker, string language, LanguageSpeakerComponent? languageComp = null) - { - if (!CanSpeak(speaker, language)) - return; - - if (languageComp == null && !TryComp(speaker, out languageComp)) - return; - - if (languageComp.CurrentLanguage == language) - return; - - languageComp.CurrentLanguage = language; - - RaiseLocalEvent(speaker, new LanguagesUpdateEvent(), true); - } - - /// - /// Adds a new language to the lists of understood and/or spoken languages of the given component. - /// - public void AddLanguage(LanguageSpeakerComponent comp, string language, bool addSpoken = true, bool addUnderstood = true) - { - if (addSpoken && !comp.SpokenLanguages.Contains(language, StringComparer.Ordinal)) - comp.SpokenLanguages.Add(language); - - if (addUnderstood && !comp.UnderstoodLanguages.Contains(language, StringComparer.Ordinal)) - comp.UnderstoodLanguages.Add(language); - - RaiseLocalEvent(comp.Owner, new LanguagesUpdateEvent(), true); - } - - private static bool IsSentenceEnd(char ch) - { - return ch is '.' or '!' or '?'; - } - - // This event is reused because re-allocating it each time is way too costly. - private readonly DetermineEntityLanguagesEvent _determineLanguagesEvent = new(string.Empty, new(), new()); - - /// - /// Returns a pair of (spoken, understood) languages of the given entity. - /// - public (List, List) GetAllLanguages(EntityUid speaker) - { - var languages = GetLanguages(speaker); - if (languages == null) - return (new(), new()); - - // The lists need to be copied because the internal ones are re-used for performance reasons. - return (new List(languages.SpokenLanguages), new List(languages.UnderstoodLanguages)); - } - - /// - /// Dynamically resolves the current language of the entity and the list of all languages it speaks. - /// The returned event is reused and thus must not be held as a reference anywhere but inside the caller function. - /// - private DetermineEntityLanguagesEvent? GetLanguages(EntityUid speaker, LanguageSpeakerComponent? comp = null) - { - if (comp == null && !TryComp(speaker, out comp)) - return null; - - var ev = _determineLanguagesEvent; - ev.SpokenLanguages.Clear(); - ev.UnderstoodLanguages.Clear(); - - ev.CurrentLanguage = comp.CurrentLanguage; - ev.SpokenLanguages.AddRange(comp.SpokenLanguages); - ev.UnderstoodLanguages.AddRange(comp.UnderstoodLanguages); - - RaiseLocalEvent(speaker, ev, true); - - if (ev.CurrentLanguage.Length == 0) - ev.CurrentLanguage = !string.IsNullOrEmpty(comp.CurrentLanguage) ? comp.CurrentLanguage : UniversalPrototype; // Fall back to account for admemes like admins possessing a bread - return ev; - } - - /// - /// Generates a stable pseudo-random number in the range [min, max) for the given seed. Each input seed corresponds to exactly one random number. - /// private int PseudoRandomNumber(int seed, int min, int max) { // This is not a uniform distribution, but it shouldn't matter: given there's 2^31 possible random numbers, // The bias of this function should be so tiny it will never be noticed. - seed += RandomRoundSeed; + seed += Seed; var random = ((seed * 1103515245) + 12345) & 0x7fffffff; // Source: http://cs.uccs.edu/~cs591/bufferOverflow/glibc-2.2.4/stdlib/random_r.c return random % (max - min) + min; } - - /// - /// Ensures the given entity has a valid language as its current language. - /// If not, sets it to the first entry of its SpokenLanguages list, or universal if it's empty. - /// - public void EnsureValidLanguage(EntityUid entity, LanguageSpeakerComponent? comp = null) - { - if (comp == null && !TryComp(entity, out comp)) - return; - - var langs = GetLanguages(entity, comp); - - if (langs != null && !langs.SpokenLanguages.Contains(comp!.CurrentLanguage, StringComparer.Ordinal)) - { - comp.CurrentLanguage = langs.SpokenLanguages.FirstOrDefault(UniversalPrototype); - } - } - - /// - /// Raised in order to determine the language an entity speaks at the current moment, - /// as well as the list of all languages the entity may speak and understand. - /// - public sealed class DetermineEntityLanguagesEvent : EntityEventArgs - { - /// - /// The default language of this entity. If empty, remain unchanged. - /// This field has no effect if the entity decides to speak in a concrete language. - /// - public string CurrentLanguage; - /// - /// The list of all languages the entity may speak. Must NOT be held as a reference! - /// - public List SpokenLanguages; - /// - /// The list of all languages the entity may understand. Must NOT be held as a reference! - /// - public List UnderstoodLanguages; - - public DetermineEntityLanguagesEvent(string currentLanguage, List spokenLanguages, List understoodLanguages) - { - CurrentLanguage = currentLanguage; - SpokenLanguages = spokenLanguages; - UnderstoodLanguages = understoodLanguages; - } - } } diff --git a/Content.Server/ADT/Language/TranslatorImplantSystem.cs b/Content.Server/ADT/Language/TranslatorImplantSystem.cs new file mode 100644 index 00000000000..2c4b97672ed --- /dev/null +++ b/Content.Server/ADT/Language/TranslatorImplantSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Implants; + +namespace Content.Server.Implants; + +public sealed class TranslatorImplantSystem : SharedTranslatorImplantSystem +{ + +} diff --git a/Content.Server/ADT/Language/TranslatorImplanterSystem.cs b/Content.Server/ADT/Language/TranslatorImplanterSystem.cs deleted file mode 100644 index f24a013cc26..00000000000 --- a/Content.Server/ADT/Language/TranslatorImplanterSystem.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Linq; -using Content.Server.Administration.Logs; -using Content.Server.Popups; -using Content.Shared.Database; -using Content.Shared.Interaction; -using Content.Shared.Language; -using Content.Shared.Language.Components; -using Content.Shared.Language.Systems; -using Content.Shared.Mobs.Components; - -namespace Content.Server.Language; - -public sealed class TranslatorImplanterSystem : SharedTranslatorImplanterSystem -{ - [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly LanguageSystem _language = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnImplant); - } - - private void OnImplant(EntityUid implanter, TranslatorImplanterComponent component, AfterInteractEvent args) - { - if (component.Used || !args.CanReach || args.Target is not { Valid: true } target) - return; - - if (!TryComp(target, out var speaker)) - return; - - if (component.MobsOnly && !HasComp(target)) - { - _popup.PopupEntity("translator-implanter-refuse", component.Owner); - return; - } - - var (_, understood) = _language.GetAllLanguages(target); - if (component.RequiredLanguages.Count > 0 && !component.RequiredLanguages.Any(lang => understood.Contains(lang))) - { - RefusesPopup(implanter, target); - return; - } - - var intrinsic = EnsureComp(target); - intrinsic.Enabled = true; - - foreach (var lang in component.SpokenLanguages.Where(lang => !intrinsic.SpokenLanguages.Contains(lang))) - intrinsic.SpokenLanguages.Add(lang); - - foreach (var lang in component.UnderstoodLanguages.Where(lang => !intrinsic.UnderstoodLanguages.Contains(lang))) - intrinsic.UnderstoodLanguages.Add(lang); - - component.Used = true; - SuccessPopup(implanter, target); - - _adminLogger.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(args.User):player} used {ToPrettyString(implanter):implanter} to give {ToPrettyString(target):target} the following languages:" - + $"\nSpoken: {string.Join(", ", component.SpokenLanguages)}; Understood: {string.Join(", ", component.UnderstoodLanguages)}"); - - OnAppearanceChange(implanter, component); - RaiseLocalEvent(target, new SharedLanguageSystem.LanguagesUpdateEvent(), true); - } - - private void RefusesPopup(EntityUid implanter, EntityUid target) - { - _popup.PopupEntity( - Loc.GetString("translator-implanter-refuse", ("implanter", implanter), ("target", target)), - implanter); - } - - private void SuccessPopup(EntityUid implanter, EntityUid target) - { - _popup.PopupEntity( - Loc.GetString("translator-implanter-success", ("implanter", implanter), ("target", target)), - implanter); - } -} diff --git a/Content.Server/ADT/Language/TranslatorSystem.cs b/Content.Server/ADT/Language/TranslatorSystem.cs index 7e3b8cfd0a7..6179395108f 100644 --- a/Content.Server/ADT/Language/TranslatorSystem.cs +++ b/Content.Server/ADT/Language/TranslatorSystem.cs @@ -1,142 +1,23 @@ -using System.Linq; using Content.Server.Popups; using Content.Server.PowerCell; -using Content.Shared.Hands; using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Inventory; -using Content.Shared.Inventory.Events; using Content.Shared.Language; -using Content.Shared.Language.Components; -using Content.Shared.Language.Systems; using Content.Shared.PowerCell; -using static Content.Server.Language.LanguageSystem; -using HandheldTranslatorComponent = Content.Shared.Language.Components.HandheldTranslatorComponent; -using HoldsTranslatorComponent = Content.Shared.Language.Components.HoldsTranslatorComponent; -using IntrinsicTranslatorComponent = Content.Shared.Language.Components.IntrinsicTranslatorComponent; namespace Content.Server.Language; -// this does not support holding multiple translators at once yet. -// that should not be an issue for now, but it better get fixed later. public sealed class TranslatorSystem : SharedTranslatorSystem { [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly LanguageSystem _language = default!; [Dependency] private readonly PowerCellSystem _powerCell = default!; - private ISawmill _sawmill = default!; - public override void Initialize() { base.Initialize(); - _sawmill = Logger.GetSawmill("translator"); - - // I wanna die. But my death won't help us discover polymorphism. - SubscribeLocalEvent(ApplyTranslation); - SubscribeLocalEvent(ApplyTranslation); - SubscribeLocalEvent(ApplyTranslation); - // TODO: make this thing draw power - // SubscribeLocalEvent(...); SubscribeLocalEvent(OnTranslatorToggle); SubscribeLocalEvent(OnPowerCellSlotEmpty); - - SubscribeLocalEvent( - (uid, component, args) => TranslatorEquipped(args.User, uid, component)); - SubscribeLocalEvent( - (uid, component, args) => TranslatorUnequipped(args.User, uid, component)); - } - - private void ApplyTranslation(EntityUid uid, IntrinsicTranslatorComponent component, - DetermineEntityLanguagesEvent ev) - { - if (!component.Enabled) - return; - - if (!_powerCell.HasActivatableCharge(uid)) - return; - - var addUnderstood = true; - var addSpoken = true; - if (component.RequiredLanguages.Count > 0) - { - if (component.RequiresAllLanguages) - { - // Add langs when the wielder has all of the required languages - foreach (var language in component.RequiredLanguages) - { - if (!ev.SpokenLanguages.Contains(language, StringComparer.Ordinal)) - addSpoken = false; - - if (!ev.UnderstoodLanguages.Contains(language, StringComparer.Ordinal)) - addUnderstood = false; - } - } - else - { - // Add langs when the wielder has at least one of the required languages - addUnderstood = false; - addSpoken = false; - foreach (var language in component.RequiredLanguages) - { - if (ev.SpokenLanguages.Contains(language, StringComparer.Ordinal)) - addSpoken = true; - - if (ev.UnderstoodLanguages.Contains(language, StringComparer.Ordinal)) - addUnderstood = true; - } - } - } - - if (addSpoken) - { - foreach (var language in component.SpokenLanguages) - { - AddIfNotExists(ev.SpokenLanguages, language); - } - - if (component.CurrentSpeechLanguage != null && ev.CurrentLanguage.Length == 0) - { - ev.CurrentLanguage = component.CurrentSpeechLanguage; - } - } - - if (addUnderstood) - { - foreach (var language in component.UnderstoodLanguages) - { - AddIfNotExists(ev.UnderstoodLanguages, language); - } - } - } - - private void TranslatorEquipped(EntityUid holder, EntityUid translator, HandheldTranslatorComponent component) - { - if (!EntityManager.HasComponent(holder)) - return; - - var intrinsic = EntityManager.EnsureComponent(holder); - UpdateBoundIntrinsicComp(component, intrinsic, component.Enabled); - - UpdatedLanguages(holder); - } - - private void TranslatorUnequipped(EntityUid holder, EntityUid translator, HandheldTranslatorComponent component) - { - if (!EntityManager.TryGetComponent(holder, out var intrinsic)) - return; - - if (intrinsic.Issuer == component) - { - - intrinsic.Enabled = false; - EntityManager.RemoveComponent(holder, intrinsic); - } - - _language.EnsureValidLanguage(holder); - - UpdatedLanguages(holder); } private void OnTranslatorToggle(EntityUid translator, HandheldTranslatorComponent component, ActivateInWorldEvent args) @@ -146,98 +27,21 @@ private void OnTranslatorToggle(EntityUid translator, HandheldTranslatorComponen var hasPower = _powerCell.HasDrawCharge(translator); - if (Transform(args.Target).ParentUid is { Valid: true } holder && EntityManager.HasComponent(holder)) - { - // This translator is held by a language speaker and thus has an intrinsic counterpart bound to it. Make sure it's up-to-date. - var intrinsic = EntityManager.EnsureComponent(holder); - var isEnabled = !component.Enabled; - if (intrinsic.Issuer != component) - { - // The intrinsic comp wasn't owned by this handheld component, so this comp wasn't the active translator. - // Thus it needs to be turned on regardless of its previous state. - intrinsic.Issuer = component; - isEnabled = true; - } - - isEnabled &= hasPower; - UpdateBoundIntrinsicComp(component, intrinsic, isEnabled); - component.Enabled = isEnabled; - _powerCell.SetDrawEnabled(translator, isEnabled); - - _language.EnsureValidLanguage(holder); - UpdatedLanguages(holder); - } - else + if (hasPower) { - // This is a standalone translator (e.g. lying on the ground). Simply toggle its state. - component.Enabled = !component.Enabled && hasPower; - _powerCell.SetDrawEnabled(translator, !component.Enabled && hasPower); + component.Enabled = !component.Enabled; + //_powerCell.SetPowerCellDrawEnabled(translator, component.Enabled); + var popupMessage = Loc.GetString(component.Enabled ? "translator-component-turnon" : "translator-component-shutoff", ("translator", component.Owner)); + _popup.PopupEntity(popupMessage, component.Owner, args.User); } OnAppearanceChange(translator, component); - - // HasPower shows a popup when there's no power, so we do not proceed in that case - if (hasPower) - { - var message = - Loc.GetString(component.Enabled ? "translator-component-turnon" : "translator-component-shutoff", ("translator", component.Owner)); - _popup.PopupEntity(message, component.Owner, args.User); - } } private void OnPowerCellSlotEmpty(EntityUid translator, HandheldTranslatorComponent component, PowerCellSlotEmptyEvent args) { component.Enabled = false; - _powerCell.SetDrawEnabled(translator, false); + //_powerCell.SetPowerCellDrawEnabled(translator, false); OnAppearanceChange(translator, component); - - if (Transform(translator).ParentUid is { Valid: true } holder && EntityManager.HasComponent(holder)) - { - if (!EntityManager.TryGetComponent(holder, out var intrinsic)) - return; - - if (intrinsic.Issuer == component) - { - intrinsic.Enabled = false; - EntityManager.RemoveComponent(holder, intrinsic); - } - - _language.EnsureValidLanguage(holder); - UpdatedLanguages(holder); - } - } - - /// - /// Copies the state from the handheld [comp] to the [intrinsic] comp, using [isEnabled] as the enabled state. - /// - private void UpdateBoundIntrinsicComp(HandheldTranslatorComponent comp, HoldsTranslatorComponent intrinsic, bool isEnabled) - { - if (isEnabled) - { - intrinsic.SpokenLanguages = new List(comp.SpokenLanguages); - intrinsic.UnderstoodLanguages = new List(comp.UnderstoodLanguages); - intrinsic.CurrentSpeechLanguage = comp.CurrentSpeechLanguage; - } - else - { - intrinsic.SpokenLanguages.Clear(); - intrinsic.UnderstoodLanguages.Clear(); - intrinsic.CurrentSpeechLanguage = null; - } - - intrinsic.Enabled = isEnabled; - intrinsic.Issuer = comp; - } - - private static void AddIfNotExists(List list, string item) - { - if (list.Contains(item)) - return; - list.Add(item); - } - - private void UpdatedLanguages(EntityUid uid) - { - RaiseLocalEvent(uid, new SharedLanguageSystem.LanguagesUpdateEvent(), true); } } diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 45706a6d754..f9423ec1ca8 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -11,7 +11,6 @@ using Content.Server.Speech.EntitySystems; using Content.Server.Station.Components; using Content.Server.Station.Systems; -using Content.Server.Language; using Content.Shared.ActionBlocker; using Content.Shared.Administration; using Content.Shared.CCVar; @@ -27,7 +26,6 @@ using Content.Shared.Radio; using Content.Shared.Speech; using Content.Shared.Whitelist; -using Content.Shared.Language; using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; @@ -39,6 +37,8 @@ using Robust.Shared.Random; using Robust.Shared.Replays; using Robust.Shared.Utility; +using Content.Shared.Language; // Lang affected +using Content.Server.Language; // Lang affected namespace Content.Server.Chat.Systems; @@ -62,18 +62,17 @@ public sealed partial class ChatSystem : SharedChatSystem [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ReplacementAccentSystem _wordreplacement = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; [Dependency] private readonly ExamineSystemShared _examineSystem = default!; - [Dependency] private readonly LanguageSystem _language = default!; + [Dependency] private readonly LanguageSystem _language = default!; // Lang affected - // Corvax-TTS-Start: Moved from Server to Shared - // public const int VoiceRange = 10; // how far voice goes in world units - // public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units - // public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units - // Corvax-TTS-End - public const string DefaultAnnouncementSound = "/Audio/Corvax/Announcements/announce.ogg"; // Corvax-Announcements - public const string CentComAnnouncementSound = "/Audio/Corvax/Announcements/centcomm.ogg"; // Corvax-Announcements + + public const int VoiceRange = 10; // how far voice goes in world units + public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units + public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units + public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg"; private bool _loocEnabled = true; private bool _deadLoocEnabled; @@ -153,9 +152,10 @@ public void TrySendInGameICMessage( IConsoleShell? shell = null, ICommonSession? player = null, string? nameOverride = null, bool checkRadioPrefix = true, - bool ignoreActionBlocker = false) + bool ignoreActionBlocker = false, + LanguagePrototype? language = null) // Lang affected { - TrySendInGameICMessage(source, message, desiredType, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, hideLog, shell, player, nameOverride, checkRadioPrefix, ignoreActionBlocker); + TrySendInGameICMessage(source, message, desiredType, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, hideLog, shell, player, nameOverride, checkRadioPrefix, ignoreActionBlocker, language); // Lang affected } /// @@ -180,7 +180,8 @@ public void TrySendInGameICMessage( string? nameOverride = null, bool checkRadioPrefix = true, bool ignoreActionBlocker = false, - LanguagePrototype? languageOverride = null) // Frontier - languages mechanic + LanguagePrototype? language = null // Lang affected + ) { if (HasComp(source)) { @@ -223,13 +224,17 @@ public void TrySendInGameICMessage( message = message[1..]; } + // Lang start + bool shouldCapitalize = (desiredType != InGameICChatType.Emote); bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); // Capitalizing the word I only happens in English, so we check language here bool shouldCapitalizeTheWordI = (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en"); - message = SanitizeInGameICMessage(source, message, out var emoteStr, shouldCapitalize, shouldPunctuate, shouldCapitalizeTheWordI); + string sanitizedMessage = SanitizeInGameICMessage(source, message, out var emoteStr, shouldCapitalize, shouldPunctuate, shouldCapitalizeTheWordI); + + // Lang end // Was there an emote in the message? If so, send it. if (player != null && emoteStr != message && emoteStr != null) @@ -244,7 +249,7 @@ public void TrySendInGameICMessage( // 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)) + if (TryProccessRadioMessage(source, sanitizedMessage, out var modMessage, out var channel)) // Accent fix { SendEntityWhisper(source, modMessage, range, channel, nameOverride, hideLog, ignoreActionBlocker); return; @@ -255,13 +260,13 @@ public void TrySendInGameICMessage( switch (desiredType) { case InGameICChatType.Speak: - SendEntitySpeak(source, message, range, nameOverride, hideLog, ignoreActionBlocker, languageOverride: languageOverride); + SendEntitySpeak(source, message, range, nameOverride, hideLog, ignoreActionBlocker, language); // Lang affected break; case InGameICChatType.Whisper: - SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker, languageOverride: languageOverride); + SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker, language); // Lang affected break; case InGameICChatType.Emote: - SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); + SendEntityEmote(source, sanitizedMessage, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); // Accent fix break; } } @@ -324,20 +329,17 @@ public void TrySendInGameOOCMessage( /// Optional color for the announcement message public void DispatchGlobalAnnouncement( string message, - string? sender = null, + string sender = "Central Command", bool playSound = true, SoundSpecifier? announcementSound = null, Color? colorOverride = null ) { - sender ??= Loc.GetString("chat-manager-sender-announcement"); - var wrappedMessage = Loc.GetString("chat-manager-sender-announcement-wrap-message", ("sender", sender), ("message", FormattedMessage.EscapeText(message))); _chatManager.ChatMessageToAll(ChatChannel.Radio, message, wrappedMessage, default, false, true, colorOverride); if (playSound) { - if (sender == Loc.GetString("admin-announce-announcer-default")) announcementSound = new SoundPathSpecifier(CentComAnnouncementSound); // Corvax-Announcements: Support custom alert sound from admin panel - _audio.PlayGlobal(announcementSound?.GetSound() ?? DefaultAnnouncementSound, Filter.Broadcast(), true, announcementSound?.Params ?? AudioParams.Default.WithVolume(-2f)); + _audio.PlayGlobal(announcementSound?.GetSound() ?? DefaultAnnouncementSound, Filter.Broadcast(), true, AudioParams.Default.WithVolume(-2f)); } _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Global station announcement from {sender}: {message}"); } @@ -353,13 +355,11 @@ public void DispatchGlobalAnnouncement( public void DispatchStationAnnouncement( EntityUid source, string message, - string? sender = null, + string sender = "Central Command", bool playDefaultSound = true, SoundSpecifier? announcementSound = null, Color? colorOverride = null) { - sender ??= Loc.GetString("chat-manager-sender-announcement"); - var wrappedMessage = Loc.GetString("chat-manager-sender-announcement-wrap-message", ("sender", sender), ("message", FormattedMessage.EscapeText(message))); var station = _stationSystem.GetOwningStation(source); @@ -386,7 +386,7 @@ public void DispatchStationAnnouncement( #endregion #region Private API - + private void SendEntitySpeak( EntityUid source, string originalMessage, @@ -394,7 +394,7 @@ private void SendEntitySpeak( string? nameOverride, bool hideLog = false, bool ignoreActionBlocker = false, - LanguagePrototype? languageOverride = null // Frontier: languages mechanic + LanguagePrototype? language = null // Lang affected ) { if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker) @@ -405,6 +405,11 @@ private void SendEntitySpeak( if (message.Length == 0) return; + // Lang start + if (language == null) + language = _language.GetCurrentLanguage(source); + // Lang end + var speech = GetSpeechVerb(source, message); // get the entity's apparent name (if no override provided). @@ -422,31 +427,48 @@ private void SendEntitySpeak( if (nameEv.SpeechVerb != null && _prototypeManager.TryIndex(nameEv.SpeechVerb, out var proto)) speech = proto; } + // Lang start + + // Accent fix start + bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); + // Capitalizing the word I only happens in English, so we check language here + bool shouldCapitalizeTheWordI = (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") + || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en"); - // Frontier - languages mechanic - var language = languageOverride ?? _language.GetLanguage(source); + string coloredMessage = SanitizeInGameICMessage(source, FormattedMessage.EscapeText(message), out _, true, shouldPunctuate, shouldCapitalizeTheWordI); + // Accent fix end - name = FormattedMessage.EscapeText(name); + string coloredLanguageMessage = SanitizeInGameICMessage(source, _language.ObfuscateMessage(source, FormattedMessage.EscapeText(message), language), out _); - // Frontier: languages mechanic ADT Upd start - if (TryComp(source, out var lang) && lang.CurrentLanguage != "GalacticCommon" && lang.CurrentLanguage != "Universal") - name = $"{lang.LocalizedID}|{name}"; - // Frontier: languages mechanic ADT Upd end + coloredMessage = FormattedMessage.EscapeText(coloredMessage); + coloredLanguageMessage = FormattedMessage.EscapeText(coloredLanguageMessage); + if (language.Color != null) + { + coloredMessage = "[color=" + language.Color.Value.ToHex().ToString() + "]" + coloredMessage + "[/color]"; + coloredLanguageMessage = "[color=" + language.Color.Value.ToHex().ToString() + "]" + coloredLanguageMessage + "[/color]"; + } + // Lang end + + name = FormattedMessage.EscapeText(name); var wrappedMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", ("entityName", name), ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), ("fontType", speech.FontId), ("fontSize", speech.FontSize), - ("message", FormattedMessage.EscapeText(message))); - - var encodedMessage = _language.ObfuscateSpeech(source, message, language); - var wrappedEncodedMessage = WrapPublicMessage(source, name, encodedMessage); + ("message", coloredMessage)); // Lang affected - // Frontier: languages mechanic - SendInVoiceRange(ChatChannel.Local, message, wrappedMessage, encodedMessage, wrappedEncodedMessage, source, range, languageOverride: language); + // Lang start + var wrappedLanguageMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", + ("entityName", name), + ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), + ("fontType", speech.FontId), + ("fontSize", speech.FontSize), + ("message", coloredLanguageMessage)); + // Lang end + SendInVoiceRange(ChatChannel.Local, message, wrappedMessage, wrappedLanguageMessage, source, range, language: language); // Lang affected - var ev = new EntitySpokeEvent(source, message, originalMessage, encodedMessage, null, language, null); + var ev = new EntitySpokeEvent(source, message, language, null, null); RaiseLocalEvent(source, ev, true); // To avoid logging any messages sent by entities that are not players, like vendors, cloning, etc. @@ -480,7 +502,7 @@ private void SendEntityWhisper( string? nameOverride, bool hideLog = false, bool ignoreActionBlocker = false, - LanguagePrototype? languageOverride = null // Frontier: languages mechanic + LanguagePrototype? language = null // Lang affected ) { if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker) @@ -492,6 +514,14 @@ private void SendEntityWhisper( var obfuscatedMessage = ObfuscateMessageReadability(message, 0.2f); + // Lang start + if (language == null) + language = _language.GetCurrentLanguage(source); + + var languageMessage = SanitizeInGameICMessage(source, _language.ObfuscateMessage(source, message, language), out _); + var obfuscatedLanguageMessage = ObfuscateMessageReadability(SanitizeInGameICMessage(source, _language.ObfuscateMessage(source, message, language), out _), 0.2f); + // Lang end + // get the entity's name by visual identity (if no override provided). string nameIdentity = FormattedMessage.EscapeText(nameOverride ?? Identity.Name(source, EntityManager)); // get the entity's name by voice (if no override provided). @@ -506,17 +536,57 @@ private void SendEntityWhisper( RaiseLocalEvent(source, nameEv); name = nameEv.Name; } + // Lang start + + // Accent fix start + bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); + // Capitalizing the word I only happens in English, so we check language here + bool shouldCapitalizeTheWordI = (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") + || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en"); + + string coloredMessage = SanitizeInGameICMessage(source, FormattedMessage.EscapeText(message), out _, true, shouldPunctuate, shouldCapitalizeTheWordI); + string coloredObfuscatedMessage = SanitizeInGameICMessage(source, FormattedMessage.EscapeText(obfuscatedMessage), out _, true, shouldPunctuate, shouldCapitalizeTheWordI); + // Accent fix end + + string coloredObfuscatedLanguageMessage = FormattedMessage.EscapeText(obfuscatedLanguageMessage); + string coloredLanguageMessage = FormattedMessage.EscapeText(languageMessage); + + coloredMessage = FormattedMessage.EscapeText(coloredMessage); + coloredObfuscatedMessage = FormattedMessage.EscapeText(coloredObfuscatedMessage); + coloredObfuscatedLanguageMessage = FormattedMessage.EscapeText(coloredObfuscatedLanguageMessage); + coloredLanguageMessage = FormattedMessage.EscapeText(coloredLanguageMessage); + + if (language.WhisperColor != null) + { + coloredMessage = "[color=" + language.WhisperColor.Value.ToHex().ToString() + "]" + coloredMessage + "[/color]"; + coloredObfuscatedMessage = "[color=" + language.WhisperColor.Value.ToHex().ToString() + "]" + coloredObfuscatedMessage + "[/color]"; + coloredObfuscatedLanguageMessage = "[color=" + language.WhisperColor.Value.ToHex().ToString() + "]" + coloredObfuscatedLanguageMessage + "[/color]"; + coloredLanguageMessage = "[color=" + language.WhisperColor.Value.ToHex().ToString() + "]" + coloredLanguageMessage + "[/color]"; + } + name = FormattedMessage.EscapeText(name); - - // Frontier: languages mechanic ADT Upd start - if (TryComp(source, out var lang) && lang.CurrentLanguage != "GalacticCommon" && lang.CurrentLanguage != "Universal") - name = $"{lang.LocalizedID}|{name}"; - // Frontier: languages mechanic ADT Upd end - // Frontier - languages mechanic (+ everything in the foreach loop) - var language = languageOverride ?? _language.GetLanguage(source); - var languageEncodedMessage = _language.ObfuscateSpeech(source, message, language); + var wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", + ("entityName", name), ("message", coloredMessage)); + + var wrappedobfuscatedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", + ("entityName", nameIdentity), ("message", coloredObfuscatedMessage)); + var wrappedUnknownMessage = Loc.GetString("chat-manager-entity-whisper-unknown-wrap-message", + ("message", coloredObfuscatedMessage)); + + var wrappedLanguageMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", + ("entityName", name), ("message", coloredLanguageMessage)); + + var wrappedobfuscatedLanguageMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", + ("entityName", nameIdentity), ("message", coloredObfuscatedLanguageMessage)); + + var wrappedUnknownLanguageMessage = Loc.GetString("chat-manager-entity-whisper-unknown-wrap-message", + ("message", coloredObfuscatedLanguageMessage)); + + if (language == null) + language = _language.GetCurrentLanguage(source); + // Lang end foreach (var (session, data) in GetRecipients(source, WhisperMuffledRange)) { EntityUid listener; @@ -528,42 +598,35 @@ private void SendEntityWhisper( if (MessageRangeCheck(session, data, range) != MessageRangeCheckResult.Full) continue; // Won't get logged to chat, and ghosts are too far away to see the pop-up, so we just won't send it to them. - var canUnderstand = _language.CanUnderstand(listener, language); - var _message = canUnderstand ? message : languageEncodedMessage; - - if (data.Range <= WhisperClearRange) + // Lang start + if (!_language.CanUnderstand(source, language) && !_language.CheckTranslators(listener, source, language)) { - var wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("entityName", name), ("message", FormattedMessage.EscapeText(_message))); - - _chatManager.ChatMessageToOne(ChatChannel.Whisper, _message, wrappedMessage, source, false, session.Channel); - } - //If listener is too far, they only hear fragments of the message - else if (_examineSystem.InRangeUnOccluded(source, listener, WhisperMuffledRange)) - { - var _obfuscatedMessage = ObfuscateMessageReadability(_message, 0.2f); - - var wrappedobfuscatedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("entityName", nameIdentity), ("message", FormattedMessage.EscapeText(_obfuscatedMessage))); - _chatManager.ChatMessageToOne(ChatChannel.Whisper, _obfuscatedMessage, wrappedobfuscatedMessage, source, false, session.Channel); + if (data.Range <= WhisperClearRange) + _chatManager.ChatMessageToOne(ChatChannel.Whisper, message, wrappedLanguageMessage, source, false, session.Channel); + //If listener is too far, they only hear fragments of the message + else if (_examineSystem.InRangeUnOccluded(source, listener, WhisperMuffledRange)) + _chatManager.ChatMessageToOne(ChatChannel.Whisper, obfuscatedMessage, wrappedobfuscatedLanguageMessage, source, false, session.Channel); + //If listener is too far and has no line of sight, they can't identify the whisperer's identity + else + _chatManager.ChatMessageToOne(ChatChannel.Whisper, obfuscatedMessage, wrappedUnknownLanguageMessage, source, false, session.Channel); } - //If listener is too far and has no line of sight, they can't identify the whisperer's identity else { - var _obfuscatedMessage = ObfuscateMessageReadability(_message, 0.2f); - - var wrappedUnknownMessage = Loc.GetString("chat-manager-entity-whisper-unknown-wrap-message", - ("message", FormattedMessage.EscapeText(_obfuscatedMessage))); - _chatManager.ChatMessageToOne(ChatChannel.Whisper, _obfuscatedMessage, wrappedUnknownMessage, source, false, session.Channel); + if (data.Range <= WhisperClearRange) + _chatManager.ChatMessageToOne(ChatChannel.Whisper, message, wrappedMessage, source, false, session.Channel); + //If listener is too far, they only hear fragments of the message + else if (_examineSystem.InRangeUnOccluded(source, listener, WhisperMuffledRange)) + _chatManager.ChatMessageToOne(ChatChannel.Whisper, obfuscatedMessage, wrappedobfuscatedMessage, source, false, session.Channel); + //If listener is too far and has no line of sight, they can't identify the whisperer's identity + else + _chatManager.ChatMessageToOne(ChatChannel.Whisper, obfuscatedMessage, wrappedUnknownMessage, source, false, session.Channel); } + // Lang end } - var replayWrap = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("entityName", name), - ("message", FormattedMessage.EscapeText(message))); - _replay.RecordServerMessage(new ChatMessage(ChatChannel.Whisper, message, replayWrap, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); + _replay.RecordServerMessage(new ChatMessage(ChatChannel.Whisper, message, wrappedMessage, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); - var ev = new EntitySpokeEvent(source, message, originalMessage, languageEncodedMessage, channel, language, obfuscatedMessage); + var ev = new EntitySpokeEvent(source, message, language, channel, obfuscatedMessage); RaiseLocalEvent(source, ev, true); if (!hideLog) if (originalMessage == message) @@ -610,7 +673,7 @@ private void SendEntityEmote( if (checkEmote) TryEmoteChatInput(source, action); - SendInVoiceRange(ChatChannel.Emotes, action, wrappedMessage,encodedMessage: string.Empty, wrappedEncodedMessage: string.Empty, source, range, author); + SendInVoiceRange(ChatChannel.Emotes, action, wrappedMessage, wrappedMessage, source, range, author, ignoreLanguage: true); // Lang affected if (!hideLog) if (name != Name(source)) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}"); @@ -637,12 +700,7 @@ private void SendLOOC(EntityUid source, ICommonSession player, string message, b ("entityName", name), ("message", FormattedMessage.EscapeText(message))); - SendInVoiceRange(ChatChannel.LOOC, message, wrappedMessage, - encodedMessage: string.Empty, - wrappedEncodedMessage: string.Empty, - source, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, - player.UserId, - languageOverride: LanguageSystem.Universal); + SendInVoiceRange(ChatChannel.LOOC, message, wrappedMessage, wrappedMessage, source, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, player.UserId, ignoreLanguage: true); // Lang affected _adminLogger.Add(LogType.Chat, LogImpact.Low, $"LOOC from {player:Player}: {message}"); } @@ -723,32 +781,36 @@ 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 message, string wrappedMessage, string encodedMessage, string wrappedEncodedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null) + private void SendInVoiceRange(ChatChannel channel, string message, string wrappedMessage, string wrappedLanguageMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? language = null, bool ignoreLanguage = false) // Lang affected { - - var language = languageOverride ?? _language.GetLanguage(source); // frontier + // Lang start + if (language == null) + language = _language.GetCurrentLanguage(source); foreach (var (session, data) in GetRecipients(source, VoiceRange)) { + EntityUid listener; + + if (session.AttachedEntity is not { Valid: true } playerEntity) + continue; + listener = session.AttachedEntity.Value; + var entRange = MessageRangeCheck(session, data, range); if (entRange == MessageRangeCheckResult.Disallowed) continue; var entHideChat = entRange == MessageRangeCheckResult.HideChat; - - // Frontier - languages mechanic - if (session.AttachedEntity is not { Valid: true } playerEntity) + if (ignoreLanguage) + { + _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author); continue; - EntityUid listener = session.AttachedEntity.Value; + } - if (channel == ChatChannel.LOOC || channel == ChatChannel.Emotes || _language.CanUnderstand(listener, language)) - { - _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.ConnectedClient, author: author); - } + if (!_language.CanUnderstand(listener, language) && !_language.CheckTranslators(listener, source, language)) + _chatManager.ChatMessageToOne(channel, message, wrappedLanguageMessage, source, entHideChat, session.Channel, author: author); else - { - _chatManager.ChatMessageToOne(channel, encodedMessage, wrappedEncodedMessage, source, entHideChat, session.ConnectedClient, author: author); - } + _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author); } + // Lang end _replay.RecordServerMessage(new ChatMessage(channel, message, wrappedMessage, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); } @@ -780,7 +842,7 @@ private bool CanSendInGame(string message, IConsoleShell? shell = null, ICommonS } // ReSharper disable once InconsistentNaming - private string SanitizeInGameICMessage(EntityUid source, string message, out string? emoteStr, bool capitalize = true, bool punctuate = false, bool capitalizeTheWordI = true) + public string SanitizeInGameICMessage(EntityUid source, string message, out string? emoteStr, bool capitalize = true, bool punctuate = false, bool capitalizeTheWordI = true) { var newMessage = message.Trim(); newMessage = SanitizeMessageReplaceWords(newMessage); @@ -857,19 +919,6 @@ public string SanitizeMessageReplaceWords(string message) return msg; } - // Frontier - languages mechanic - public string WrapPublicMessage(EntityUid source, string name, string message) - { - var speech = GetSpeechVerb(source, message); - var verbName = Loc.GetString(_random.Pick(speech.SpeechVerbStrings)); - return Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", - ("entityName", name), - ("verb", verbName), - ("fontType", speech.FontId), - ("fontSize", speech.FontSize), - ("message", FormattedMessage.EscapeText(message))); - } - /// /// Returns list of players and ranges for all players withing some range. Also returns observers with a range of -1. /// @@ -1005,23 +1054,18 @@ public sealed class EntitySpokeEvent : EntityEventArgs { public readonly EntityUid Source; public readonly string Message; - public readonly string OriginalMessage; - public readonly string LanguageEncodedMessage; - public readonly string? ObfuscatedMessage; // not null if this was a - public readonly LanguagePrototype Language; - + public readonly string? ObfuscatedMessage; // not null if this was a whisper /// /// If the entity was trying to speak into a radio, this was the channel they were trying to access. If a radio /// message gets sent on this channel, this should be set to null to prevent duplicate messages. /// public RadioChannelPrototype? Channel; + public readonly LanguagePrototype Language; - public EntitySpokeEvent(EntityUid source, string message, string originalMessage, string languageEncodedMessage, RadioChannelPrototype? channel, LanguagePrototype language, string? obfuscatedMessage) + public EntitySpokeEvent(EntityUid source, string message, LanguagePrototype language, RadioChannelPrototype? channel, string? obfuscatedMessage) { Source = source; Message = message; - OriginalMessage = originalMessage; // Corvax-TTS: Spec symbol sanitize - LanguageEncodedMessage = languageEncodedMessage; Channel = channel; ObfuscatedMessage = obfuscatedMessage; Language = language; diff --git a/Content.Server/Corvax/TTS/TTSSystem.cs b/Content.Server/Corvax/TTS/TTSSystem.cs index 81caf95b099..d18e4cbaea2 100644 --- a/Content.Server/Corvax/TTS/TTSSystem.cs +++ b/Content.Server/Corvax/TTS/TTSSystem.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Content.Server.Chat.Systems; using Content.Shared.Corvax.CCCVars; using Content.Shared.Corvax.TTS; @@ -7,6 +7,8 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Content.Server.Language; +using Content.Shared.Language; namespace Content.Server.Corvax.TTS; @@ -18,6 +20,7 @@ public sealed partial class TTSSystem : EntitySystem [Dependency] private readonly TTSManager _ttsManager = default!; [Dependency] private readonly SharedTransformSystem _xforms = default!; [Dependency] private readonly IRobustRandom _rng = default!; + [Dependency] private readonly LanguageSystem _language = default!; private readonly List _sampleText = new() @@ -33,7 +36,8 @@ public sealed partial class TTSSystem : EntitySystem "Здесь есть доктор? Человек умирает от отравленного пончика! Нужна помощь!", "Вам нужно согласие и печать квартирмейстера, если вы хотите сделать заказ на партию дробовиков.", "Возле эвакуационного шаттла разгерметизация! Инженеры, нам срочно нужна ваша помощь!", - "Бармен, налей мне самого крепкого вина, которое есть в твоих запасах!" + "Бармен, налей мне самого крепкого вина, которое есть в твоих запасах!", + "Здесь был котя." }; private const int MaxMessageChars = 100 * 2; // same as SingleBubbleCharLimit * 2 @@ -66,7 +70,7 @@ private async void OnRequestPreviewTTS(RequestPreviewTTSEvent ev, EntitySessionE if (soundData is null) return; - RaiseNetworkEvent(new PlayTTSEvent(soundData), Filter.SinglePlayer(args.SenderSession)); + RaiseNetworkEvent(new PlayTTSEvent(soundData, soundData, _prototypeManager.Index("Universal")), Filter.SinglePlayer(args.SenderSession)); } private async void OnEntitySpoke(EntityUid uid, TTSComponent component, EntitySpokeEvent args) @@ -86,30 +90,41 @@ private async void OnEntitySpoke(EntityUid uid, TTSComponent component, EntitySp if (args.ObfuscatedMessage != null) { - HandleWhisper(uid, args.Message, args.ObfuscatedMessage, protoVoice.Speaker); + HandleWhisper(uid, args.Message, args.ObfuscatedMessage, protoVoice.Speaker, args.Language); return; } - HandleSay(uid, args.Message, protoVoice.Speaker); + HandleSay(uid, args.Message, protoVoice.Speaker, args.Language); } - private async void HandleSay(EntityUid uid, string message, string speaker) + private async void HandleSay(EntityUid uid, string message, string speaker, LanguagePrototype language) { var soundData = await GenerateTTS(message, speaker); if (soundData is null) return; - RaiseNetworkEvent(new PlayTTSEvent(soundData, GetNetEntity(uid)), Filter.Pvs(uid)); + + var languageSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, message, language), speaker); + if (languageSoundData is null) return; + + + RaiseNetworkEvent(new PlayTTSEvent(soundData, languageSoundData, language, GetNetEntity(uid)), Filter.Pvs(uid)); } - private async void HandleWhisper(EntityUid uid, string message, string obfMessage, string speaker) + private async void HandleWhisper(EntityUid uid, string message, string obfMessage, string speaker, LanguagePrototype language) { var fullSoundData = await GenerateTTS(message, speaker, true); if (fullSoundData is null) return; + var fullLangSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, message, language), speaker, true); + if (fullLangSoundData is null) return; + var obfSoundData = await GenerateTTS(obfMessage, speaker, true); if (obfSoundData is null) return; - var fullTtsEvent = new PlayTTSEvent(fullSoundData, GetNetEntity(uid), true); - var obfTtsEvent = new PlayTTSEvent(obfSoundData, GetNetEntity(uid), true); + var obfLangSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, obfMessage, language), speaker, true); + if (obfLangSoundData is null) return; + + var fullTtsEvent = new PlayTTSEvent(fullSoundData, fullLangSoundData, language, GetNetEntity(uid), true); + var obfTtsEvent = new PlayTTSEvent(obfSoundData, obfLangSoundData, language, GetNetEntity(uid), true); // TODO: Check obstacles var xformQuery = GetEntityQuery(); diff --git a/Content.Server/EntityEffects/Effects/MakeSentient.cs b/Content.Server/EntityEffects/Effects/MakeSentient.cs index c4870438486..aad76a94ecf 100644 --- a/Content.Server/EntityEffects/Effects/MakeSentient.cs +++ b/Content.Server/EntityEffects/Effects/MakeSentient.cs @@ -3,6 +3,7 @@ using Content.Shared.EntityEffects; using Content.Shared.Mind.Components; using Robust.Shared.Prototypes; +using Content.Shared.Language; namespace Content.Server.EntityEffects.Effects; @@ -22,6 +23,18 @@ public override void Effect(EntityEffectBaseArgs args) entityManager.RemoveComponent(uid); entityManager.RemoveComponent(uid); + // Lang start + var lang = entityManager.EnsureComponent(uid); + if (!lang.SpokenLanguages.Contains("GalacticCommon")) + { + lang.SpokenLanguages.Add("GalacticCommon"); + } + if (!lang.UnderstoodLanguages.Contains("GalacticCommon")) + { + lang.UnderstoodLanguages.Add("GalacticCommon"); + } + // Lang end + // Stops from adding a ghost role to things like people who already have a mind if (entityManager.TryGetComponent(uid, out var mindContainer) && mindContainer.HasMind) { @@ -34,6 +47,7 @@ public override void Effect(EntityEffectBaseArgs args) return; } + ghostRole = entityManager.AddComponent(uid); entityManager.EnsureComponent(uid); diff --git a/Content.Server/Mind/Commands/MakeSentientCommand.cs b/Content.Server/Mind/Commands/MakeSentientCommand.cs index 5e19d135b6f..80a5c7b71eb 100644 --- a/Content.Server/Mind/Commands/MakeSentientCommand.cs +++ b/Content.Server/Mind/Commands/MakeSentientCommand.cs @@ -6,6 +6,7 @@ using Content.Shared.Movement.Components; using Content.Shared.Speech; using Robust.Shared.Console; +using Content.Shared.Language; namespace Content.Server.Mind.Commands { @@ -55,6 +56,18 @@ public static void MakeSentient(EntityUid uid, IEntityManager entityManager, boo { entityManager.EnsureComponent(uid); entityManager.EnsureComponent(uid); + + // Lang start + var lang = entityManager.EnsureComponent(uid); + if (!lang.SpokenLanguages.Contains("GalacticCommon")) + { + lang.SpokenLanguages.Add("GalacticCommon"); + } + if (!lang.UnderstoodLanguages.Contains("GalacticCommon")) + { + lang.UnderstoodLanguages.Add("GalacticCommon"); + } + // Lang end } entityManager.EnsureComponent(uid); diff --git a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs index d18b044205c..34a8a4c2a58 100644 --- a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs +++ b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Radio.EntitySystems; using Robust.Shared.Network; using Robust.Shared.Player; +using Content.Server.Language; namespace Content.Server.Radio.EntitySystems; @@ -14,6 +15,7 @@ public sealed class HeadsetSystem : SharedHeadsetSystem { [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly RadioSystem _radio = default!; + [Dependency] private readonly LanguageSystem _language = default!; public override void Initialize() { @@ -100,7 +102,12 @@ public void SetEnabled(EntityUid uid, bool value, HeadsetComponent? component = private void OnHeadsetReceive(EntityUid uid, HeadsetComponent component, ref RadioReceiveEvent args) { if (TryComp(Transform(uid).ParentUid, out ActorComponent? actor)) - _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel); + { + if (_language.CanUnderstand(Transform(uid).ParentUid, args.Language)) + _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel); + else + _netMan.ServerSendMessage(args.UnknownLanguageChatMsg, actor.PlayerSession.Channel); + } } private void OnEmpPulse(EntityUid uid, HeadsetComponent component, ref EmpPulseEvent args) diff --git a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs index 1258e0b8c7e..b92142aa9a2 100644 --- a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Server.Chat.Systems; using Content.Server.Interaction; +using Content.Server.Language; using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; @@ -26,6 +27,7 @@ public sealed class RadioDeviceSystem : EntitySystem [Dependency] private readonly RadioSystem _radio = default!; [Dependency] private readonly InteractionSystem _interaction = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly LanguageSystem _language = default!; // Used to prevent a shitter from using a bunch of radios to spam chat. private HashSet<(string, EntityUid)> _recentlySent = new(); @@ -215,7 +217,7 @@ private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, ref ("originalName", nameEv.Name)); // log to chat so people can identity the speaker/source, but avoid clogging ghost chat if there are many radios - _chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false); + _chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false, language: args.Language); } private void OnIntercomEncryptionChannelsChanged(Entity ent, ref EncryptionChannelsChangedEvent args) diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 3ad101e62db..f5566bcc190 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -15,6 +15,8 @@ using Robust.Shared.Random; using Robust.Shared.Replays; using Robust.Shared.Utility; +using Content.Server.Language; +using Content.Shared.Language; namespace Content.Server.Radio.EntitySystems; @@ -29,6 +31,7 @@ public sealed class RadioSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly LanguageSystem _language = default!; // set used to prevent radio feedback loops. private readonly HashSet _messages = new(); @@ -56,7 +59,12 @@ private void OnIntrinsicSpeak(EntityUid uid, IntrinsicRadioTransmitterComponent private void OnIntrinsicReceive(EntityUid uid, IntrinsicRadioReceiverComponent component, ref RadioReceiveEvent args) { if (TryComp(uid, out ActorComponent? actor)) - _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel); + { + if (_language.CanUnderstand(uid, args.Language)) + _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel); + else + _netMan.ServerSendMessage(args.UnknownLanguageChatMsg, actor.PlayerSession.Channel); + } } /// @@ -72,12 +80,14 @@ public void SendRadioMessage(EntityUid messageSource, string message, ProtoId /// Entity that spoke the message /// Entity that picked up the message and will send it, e.g. headset - public void SendRadioMessage(EntityUid messageSource, string message, RadioChannelPrototype channel, EntityUid radioSource, bool escapeMarkup = true) + public void SendRadioMessage(EntityUid messageSource, string message, RadioChannelPrototype channel, EntityUid radioSource, bool escapeMarkup = true, LanguagePrototype? languageOverride = null) { // TODO if radios ever garble / modify messages, feedback-prevention needs to be handled better than this. if (!_messages.Add(message)) return; + var language = languageOverride ?? _language.GetCurrentLanguage(messageSource); + var name = TryComp(messageSource, out VoiceMaskComponent? mask) && mask.Enabled ? mask.VoiceName : MetaData(messageSource).EntityName; @@ -99,6 +109,14 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann ? FormattedMessage.EscapeText(message) : message; + var languageEncodedContent = _language.ObfuscateMessage(messageSource, content, language); + + if (language.Color != null) + { + content = "[color=" + language.Color.Value.ToHex().ToString() + "]" + FormattedMessage.EscapeText(content) + "[/color]"; + languageEncodedContent = "[color=" + language.Color.Value.ToHex().ToString() + "]" + FormattedMessage.EscapeText(languageEncodedContent) + "[/color]"; + } + var wrappedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", ("color", channel.Color), ("fontType", speech.FontId), @@ -108,6 +126,15 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann ("name", name), ("message", content)); + var wrappedEncodedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", + ("color", channel.Color), + ("fontType", speech.FontId), + ("fontSize", speech.FontSize), + ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), + ("channel", $"\\[{channel.LocalizedName}\\]"), + ("name", name), + ("message", languageEncodedContent)); + // most radios are relayed to chat, so lets parse the chat message beforehand var chat = new ChatMessage( ChatChannel.Radio, @@ -115,8 +142,18 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann wrappedMessage, NetEntity.Invalid, null); + + var encodedChat = new ChatMessage( + ChatChannel.Radio, + message, + wrappedEncodedMessage, + NetEntity.Invalid, + null); + var chatMsg = new MsgChatMessage { Message = chat }; - var ev = new RadioReceiveEvent(message, messageSource, channel, radioSource, chatMsg); + var encodedChatMsg = new MsgChatMessage { Message = chat }; + + var ev = new RadioReceiveEvent(message, messageSource, channel, radioSource, chatMsg, encodedChatMsg, language); var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource); RaiseLocalEvent(ref sendAttemptEv); diff --git a/Content.Server/Radio/RadioEvent.cs b/Content.Server/Radio/RadioEvent.cs index fafa66674e3..fbc862df13b 100644 --- a/Content.Server/Radio/RadioEvent.cs +++ b/Content.Server/Radio/RadioEvent.cs @@ -1,10 +1,11 @@ using Content.Shared.Chat; using Content.Shared.Radio; +using Content.Shared.Language; // Lang affected namespace Content.Server.Radio; [ByRefEvent] -public readonly record struct RadioReceiveEvent(string Message, EntityUid MessageSource, RadioChannelPrototype Channel, EntityUid RadioSource, MsgChatMessage ChatMsg); +public readonly record struct RadioReceiveEvent(string Message, EntityUid MessageSource, RadioChannelPrototype Channel, EntityUid RadioSource, MsgChatMessage ChatMsg, MsgChatMessage UnknownLanguageChatMsg, LanguagePrototype Language); // Lang affected /// /// Use this event to cancel sending message per receiver diff --git a/Content.Shared/ADT/Language/Components/CommonLangUnknown.cs b/Content.Shared/ADT/Language/Components/CommonLangUnknown.cs deleted file mode 100644 index bac1230704f..00000000000 --- a/Content.Shared/ADT/Language/Components/CommonLangUnknown.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Content.Shared.Actions; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Language; - -[RegisterComponent] -public sealed partial class UnknowLanguageComponent : Component -{ - [DataField("language")] - public string LanguageToForgot = "GalacticCommon"; -} diff --git a/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs b/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs new file mode 100644 index 00000000000..86aafe3e68c --- /dev/null +++ b/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs @@ -0,0 +1,27 @@ +using Content.Shared.Actions; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Language; + +[RegisterComponent, NetworkedComponent] +public sealed partial class HandheldTranslatorComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite)] + [DataField("toUnderstand", required: true)] + public List ToUnderstand; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("toSpeak", required: true)] + public List ToSpeak; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("toggle")] + public bool ToggleOnInteract = true; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool Enabled = false; + +} diff --git a/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs b/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs index 2d3953f78ca..b524a1abe3f 100644 --- a/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs +++ b/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs @@ -1,53 +1,20 @@ -using Content.Shared.Actions; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.GameStates; namespace Content.Shared.Language; -[RegisterComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class LanguageSpeakerComponent : Component { - /// - /// The current language the entity may use to speak. - /// Other listeners will hear the entity speak in this language. - /// - [ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] - public string CurrentLanguage = default!; + public string? CurrentLanguage = default!; - /// - /// чтоб в чате видно было не айди, а название. - /// - public string LocalizedID => Loc.GetString("language-" + CurrentLanguage); - - - /// - /// List of languages this entity can speak. - /// - [ViewVariables] - [DataField("speaks", customTypeSerializer: typeof(PrototypeIdListSerializer), required: true)] + [DataField("speaks"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public List SpokenLanguages = new(); - /// - /// List of languages this entity can understand. - /// - [ViewVariables] - [DataField("understands", customTypeSerializer: typeof(PrototypeIdListSerializer), required: true)] + [DataField("understands"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public List UnderstoodLanguages = new(); - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("languageMenuAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string LanguageMenuAction = "ActionLanguageMenu"; - - [DataField] public EntityUid? Action; } - -[Serializable, NetSerializable] -public enum LanguageMenuUiKey : byte -{ - Key -} - -public sealed partial class LanguageMenuActionEvent : InstantActionEvent { } diff --git a/Content.Shared/ADT/Language/Components/TranslatorComponent.cs b/Content.Shared/ADT/Language/Components/TranslatorComponent.cs deleted file mode 100644 index a5fac7d2ff5..00000000000 --- a/Content.Shared/ADT/Language/Components/TranslatorComponent.cs +++ /dev/null @@ -1,93 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Language.Components; - -public abstract partial class BaseTranslatorComponent : Component -{ - /// - /// The language this translator changes the speaker's language to when they don't specify one. - /// If null, does not modify the default language. - /// - [DataField("default-language")] - [ViewVariables(VVAccess.ReadWrite)] - public string? CurrentSpeechLanguage = null; - - /// - /// The list of additional languages this translator allows the wielder to speak. - /// - [DataField("spoken", customTypeSerializer: typeof(PrototypeIdListSerializer))] - [ViewVariables(VVAccess.ReadWrite)] - public List SpokenLanguages = new(); - - /// - /// The list of additional languages this translator allows the wielder to understand. - /// - [DataField("understood", customTypeSerializer: typeof(PrototypeIdListSerializer))] - [ViewVariables(VVAccess.ReadWrite)] - public List UnderstoodLanguages = new(); - - /// - /// The languages the wielding MUST know in order for this translator to have effect. - /// The field [RequiresAllLanguages] indicates whether all of them are required, or just one. - /// - [DataField("requires", customTypeSerializer: typeof(PrototypeIdListSerializer))] - [ViewVariables(VVAccess.ReadWrite)] - public List RequiredLanguages = new(); - - /// - /// If true, the wielder must understand all languages in [RequiredLanguages] to speak [SpokenLanguages], - /// and understand all languages in [RequiredLanguages] to understand [UnderstoodLanguages]. - /// - /// Otherwise, at least one language must be known (or the list must be empty). - /// - [DataField("requires-all")] - [ViewVariables(VVAccess.ReadWrite)] - public bool RequiresAllLanguages = false; - - [DataField("enabled")] - public bool Enabled = true; -} - -/// -/// A translator that must be held in a hand or a pocket of an entity in order ot have effect. -/// -[RegisterComponent] -public sealed partial class HandheldTranslatorComponent : BaseTranslatorComponent -{ - /// - /// Whether or not interacting with this translator - /// toggles it on or off. - /// - [DataField("toggleOnInteract")] - public bool ToggleOnInteract = true; -} - -/// -/// A translator attached to an entity that translates its speech. -/// An example is a translator implant that allows the speaker to speak another language. -/// -[RegisterComponent, Virtual] -public partial class IntrinsicTranslatorComponent : BaseTranslatorComponent -{ -} - -/// -/// Applied internally to the holder of [HandheldTranslatorComponent]. -/// Do not use directly. Use [HandheldTranslatorComponent] instead. -/// -[RegisterComponent] -public sealed partial class HoldsTranslatorComponent : IntrinsicTranslatorComponent -{ - public Component? Issuer = null; -} - -/// -/// Applied to entities who were injected with a translator implant. -/// -[RegisterComponent] -public sealed partial class ImplantedTranslatorComponent : IntrinsicTranslatorComponent -{ -} diff --git a/Content.Shared/ADT/Language/Components/TranslatorImplantComponent.cs b/Content.Shared/ADT/Language/Components/TranslatorImplantComponent.cs new file mode 100644 index 00000000000..a7f0b597992 --- /dev/null +++ b/Content.Shared/ADT/Language/Components/TranslatorImplantComponent.cs @@ -0,0 +1,42 @@ +using Content.Shared.Actions; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Implants.Components; + +/// +/// Subdermal implants get stored in a container on an entity and grant the entity special actions +/// The actions can be activated via an action, a passive ability (ie tracking), or a reactive ability (ie on death) or some sort of combination +/// They're added and removed with implanters +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TranslatorImplantComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite)] + [DataField("toUnderstand")] + public List ToUnderstand = new(); + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("toSpeak")] + public List ToSpeak = new(); + + /// + /// The entity this implant is inside + /// + [ViewVariables, AutoNetworkedField] + public EntityUid? ImplantedEntity; + + [ViewVariables(VVAccess.ReadWrite)] + public List ImplantedToUnderstand = new(); + + [ViewVariables(VVAccess.ReadWrite)] + public List ImplantedToSpeak = new(); + + /// + /// Should this implant be removeable? + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("permanent"), AutoNetworkedField] + public bool Permanent = false; +} diff --git a/Content.Shared/ADT/Language/Components/TranslatorImplanterComponent.cs b/Content.Shared/ADT/Language/Components/TranslatorImplanterComponent.cs deleted file mode 100644 index 28ed4cce185..00000000000 --- a/Content.Shared/ADT/Language/Components/TranslatorImplanterComponent.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Language.Components; - -/// -/// An item that, when used on a mob, adds an intrinsic translator to it. -/// -[RegisterComponent] -public sealed partial class TranslatorImplanterComponent : Component -{ - [DataField("spoken", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables] - public List SpokenLanguages = new(); - - [DataField("understood", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables] - public List UnderstoodLanguages = new(); - - /// - /// The list of languages the mob must understand in order for this translator to have effect. - /// Knowing one language is enough. - /// - [DataField("requires", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables] - public List RequiredLanguages = new(); - - /// - /// If true, only allows to use this implanter on mobs. - /// - [DataField("mobs-only")] - public bool MobsOnly = true; - - /// - /// Whether this implant has been used already. - /// - public bool Used = false; -} diff --git a/Content.Shared/ADT/Language/Components/UniversalLanguageSpeacerComponent.cs b/Content.Shared/ADT/Language/Components/UniversalLanguageSpeacerComponent.cs deleted file mode 100644 index 7ef609e6ba0..00000000000 --- a/Content.Shared/ADT/Language/Components/UniversalLanguageSpeacerComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Content.Shared.Language.Components; - -// -// Signifies that this entity can speak and understand any language. -// Applies to such entities as ghosts. -// -[RegisterComponent] -public sealed partial class UniversalLanguageSpeakerComponent : Component -{ - -} diff --git a/Content.Shared/ADT/Language/LanguagePrototype.cs b/Content.Shared/ADT/Language/LanguagePrototype.cs index c160187bf62..8850ebc24c5 100644 --- a/Content.Shared/ADT/Language/LanguagePrototype.cs +++ b/Content.Shared/ADT/Language/LanguagePrototype.cs @@ -1,4 +1,6 @@ -using Robust.Shared.Prototypes; +using Robust.Shared.Prototypes; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; namespace Content.Shared.Language; @@ -8,17 +10,18 @@ public sealed class LanguagePrototype : IPrototype [IdDataField] public string ID { get; private set; } = default!; - // - // If true, obfuscated phrases of creatures speaking this language will have their syllables replaced with "replacement" syllables. - // Otherwise entire sentences will be replaced. - // - [DataField("obfuscateSyllables", required: true)] + [DataField("obfuscateSyllables")] public bool ObfuscateSyllables { get; private set; } = false; - // - // Lists all syllables that are used to obfuscate a message a listener cannot understand if obfuscateSyllables is true, - // Otherwise uses all possible phrases the creature can make when trying to say anything. - // + [DataField("show")] + public bool ShowName { get; private set; } = true; + + [DataField] + public Color? Color; + + [DataField] + public Color? WhisperColor; + [DataField("replacement", required: true)] public List Replacement = new(); diff --git a/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs b/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs index 54c33fc1859..4f940f232e2 100644 --- a/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs @@ -1,73 +1,266 @@ -using Content.Shared.Actions; +using Content.Shared.Actions; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; +using Robust.Shared.Containers; +using Content.Shared.Ghost; +using Robust.Shared.Network; -namespace Content.Shared.Language.Systems; +namespace Content.Shared.Language; public abstract class SharedLanguageSystem : EntitySystem { - [ValidatePrototypeId] - public static readonly string GalacticCommonPrototype = "GalacticCommon"; - [ValidatePrototypeId] - public static readonly string UniversalPrototype = "Universal"; - public static LanguagePrototype GalacticCommon { get; private set; } = default!; - public static LanguagePrototype Universal { get; private set; } = default!; [Dependency] private readonly SharedActionsSystem _action = default!; - [Dependency] protected readonly IPrototypeManager _prototype = default!; [Dependency] protected readonly IRobustRandom _random = default!; - protected ISawmill _sawmill = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly INetManager _netMan = default!; public override void Initialize() { - GalacticCommon = _prototype.Index("GalacticCommon"); - Universal = _prototype.Index("Universal"); - _sawmill = Logger.GetSawmill("language"); + + } + + public bool CanSpeak(EntityUid uid, LanguagePrototype proto, LanguageSpeakerComponent? component = null) + { + if (HasComp(uid)) + return false; + + if (!Resolve(uid, ref component)) + return false; - SubscribeLocalEvent(OnInit); + if (proto.ID == "Universal") + return true; + + foreach (var lang in component.SpokenLanguages) + if (lang == proto.ID) + return true; + + return false; } - public LanguagePrototype? GetLanguage(string id) + public bool CanUnderstand(EntityUid uid, LanguagePrototype proto, LanguageSpeakerComponent? component = null) { - _prototype.TryIndex(id, out var proto); - return proto; + if (HasComp(uid)) + return true; + + if (!Resolve(uid, ref component)) + return false; + + if (proto.ID == "Universal") + return true; + + foreach (var lang in component.UnderstoodLanguages) + if (lang == proto.ID) + return true; + + return false; } - private void OnInit(EntityUid uid, LanguageSpeakerComponent component, MapInitEvent args) + public bool CanSpeak(EntityUid uid, string protoId, LanguageSpeakerComponent? component = null) { - _action.AddAction(uid, ref component.Action, component.LanguageMenuAction, uid); + if (!_proto.TryIndex(protoId, out var proto)) + return false; + + if (HasComp(uid)) + return false; + + if (!Resolve(uid, ref component)) + return false; + + if (proto.ID == "Universal") + return true; + + foreach (var lang in component.SpokenLanguages) + if (lang == proto.ID) + return true; + + return false; } - /// - /// Raised on an entity when its list of languages changes. - /// - public sealed class LanguagesUpdateEvent : EntityEventArgs + public bool CanUnderstand(EntityUid uid, string protoId, LanguageSpeakerComponent? component = null) { + if (!_proto.TryIndex(protoId, out var proto)) + return false; + + if (HasComp(uid)) + return true; + + if (!Resolve(uid, ref component)) + return false; + + if (proto.ID == "Universal") + return true; + + foreach (var lang in component.UnderstoodLanguages) + if (lang == proto.ID) + return true; + + return false; } - /// - /// Sent when a client wants to update its language menu. - /// - [Serializable, NetSerializable] - public sealed class RequestLanguageMenuStateMessage : EntityEventArgs + // Unholy shit + public bool CheckTranslators(EntityUid uid, EntityUid source, LanguagePrototype proto) { + if (!TryComp(uid, out var uidManager)) + return false; + if (!TryComp(uid, out var comp)) + return false; + bool canTranslate = false; + bool canUnderstandTranslator = false; + + foreach (var container in uidManager.Containers.Values) + { + foreach (var entity in container.ContainedEntities) + { + if (TryComp(entity, out var translator) && translator.Enabled) + { + foreach (var item in translator.ToUnderstand) + { + if (item == proto.ID) + canTranslate = true; + } + if (!TryComp(uid, out var sourceLang)) + { + canUnderstandTranslator = false; + continue; + } + + foreach (var lang in translator.ToSpeak) + { + foreach (var understoodLangs in sourceLang.UnderstoodLanguages) + { + if (lang == understoodLangs) + canUnderstandTranslator = true; + } + } + + } + } + } + + if (canTranslate && canUnderstandTranslator) + return true; + + canTranslate = false; + canUnderstandTranslator = false; + + if (!TryComp(source, out var sourceManager)) + return false; + + foreach (var container in sourceManager.Containers.Values) + { + foreach (var entity in container.ContainedEntities) + { + if (TryComp(entity, out var translator) && translator.Enabled) + { + foreach (var item in translator.ToSpeak) + { + if (item == proto.ID) + canTranslate = true; + } + if (!TryComp(source, out var sourceLang)) + { + canUnderstandTranslator = false; + continue; + } + + foreach (var lang in translator.ToUnderstand) + { + foreach (var understoodLangs in sourceLang.SpokenLanguages) + { + if (lang == understoodLangs) + canUnderstandTranslator = true; + } + } + + } + } + } + + if (canTranslate && canUnderstandTranslator) + return true; + + return false; + } + + public LanguagePrototype GetCurrentLanguage(EntityUid uid) + { + var universalProto = _proto.Index("Universal"); + + if (!TryComp(uid, out var comp) || comp.CurrentLanguage == null) + return universalProto; + + if (_proto.TryIndex(comp.CurrentLanguage, out var proto)) + return proto; + + return universalProto; } - /// - /// Sent by the server when the client needs to update its language menu, - /// or directly after [RequestLanguageMenuStateMessage]. - /// - [Serializable, NetSerializable] - public sealed class LanguageMenuStateMessage : EntityEventArgs + public void SelectLanguage(NetEntity ent, string language, LanguageSpeakerComponent? component = null) { - public string CurrentLanguage; - public List Options; + var speaker = GetEntity(ent); + + if (!CanSpeak(speaker, GetLanguage(language))) + return; + + if (component == null && !TryComp(speaker, out component)) + return; + + if (component.CurrentLanguage == language) + return; - public LanguageMenuStateMessage(string currentLanguage, List options) + if (_netMan.IsClient) { - CurrentLanguage = currentLanguage; - Options = options; + component.CurrentLanguage = language; + RaiseLocalEvent(new LanguageMenuStateMessage(ent, language, component.UnderstoodLanguages)); } + + RaiseNetworkEvent(new LanguageChosenMessage(ent, language)); + } + + public LanguagePrototype GetLanguage(string id) + { + if (!_proto.TryIndex(id, out var result)) + return _proto.Index("Universal"); + + return result; + } +} + + +/// +/// Sent when a client wants to change its selected language. +/// +[Serializable, NetSerializable] +public sealed class LanguageChosenMessage : EntityEventArgs +{ + public NetEntity Uid; + public string SelectedLanguage; + + public LanguageChosenMessage(NetEntity uid, string selectedLanguage) + { + Uid = uid; + SelectedLanguage = selectedLanguage; + } +} + + +/// +/// Sent by the server when the client needs to update its language menu, +/// or directly after [RequestLanguageMenuStateMessage]. +/// +[Serializable, NetSerializable] +public sealed class LanguageMenuStateMessage : EntityEventArgs +{ + public NetEntity ComponentOwner; + public string CurrentLanguage; + public List Options; + + public LanguageMenuStateMessage(NetEntity componentOwner, string currentLanguage, List options) + { + ComponentOwner = componentOwner; + CurrentLanguage = currentLanguage; + Options = options; } } diff --git a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs new file mode 100644 index 00000000000..0fad22f50f0 --- /dev/null +++ b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs @@ -0,0 +1,113 @@ +using System.Linq; +using Content.Shared.Actions; +using Content.Shared.Implants.Components; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Mobs; +using Content.Shared.Tag; +using JetBrains.Annotations; +using Robust.Shared.Containers; +using Robust.Shared.Network; +using Content.Shared.Language; + +namespace Content.Shared.Implants; + +public abstract class SharedTranslatorImplantSystem : EntitySystem +{ + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedLanguageSystem _language = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnInsert); + SubscribeLocalEvent(OnRemoveAttempt); + SubscribeLocalEvent(OnRemove); + } + + private void OnInsert(EntityUid uid, TranslatorImplantComponent component, EntGotInsertedIntoContainerMessage args) + { + if (_net.IsClient) + return; + + if (!TryComp(args.Container.Owner, out var languageSpeaker)) + return; + + if (component.ToUnderstand.Count > 0) + { + foreach (var item in component.ToUnderstand) + { + if (_language.CanUnderstand(args.Container.Owner, _language.GetLanguage(item))) + continue; + languageSpeaker.UnderstoodLanguages.Add(item); + component.ImplantedToUnderstand.Add(item); + } + } + + if (component.ToSpeak.Count > 0) + { + foreach (var item in component.ToSpeak) + { + if (_language.CanSpeak(args.Container.Owner, _language.GetLanguage(item))) + continue; + languageSpeaker.SpokenLanguages.Add(item); + component.ImplantedToSpeak.Add(item); + } + } + + component.ImplantedEntity = args.Container.Owner; + + Dirty(component.ImplantedEntity.Value, languageSpeaker); + + var menuEv = new LanguageMenuStateMessage(GetNetEntity(component.ImplantedEntity.Value), _language.GetCurrentLanguage(component.ImplantedEntity.Value).ID, languageSpeaker.UnderstoodLanguages); + RaiseNetworkEvent(menuEv); + + var ev = new ImplantImplantedEvent(uid, component.ImplantedEntity.Value); + RaiseLocalEvent(uid, ref ev); + } + private void OnRemoveAttempt(EntityUid uid, TranslatorImplantComponent component, ContainerGettingRemovedAttemptEvent args) + { + if (component.Permanent && component.ImplantedEntity != null) + args.Cancel(); + } + + private void OnRemove(EntityUid uid, TranslatorImplantComponent component, EntGotRemovedFromContainerMessage args) + { + if (component.ImplantedEntity == null || Terminating(component.ImplantedEntity.Value)) + return; + + if (!TryComp(component.ImplantedEntity.Value, out var languageSpeaker)) + return; + + if (component.ImplantedToUnderstand.Count > 0) + { + foreach (var item in component.ImplantedToUnderstand) + { + languageSpeaker.UnderstoodLanguages.Remove(item); + } + } + + if (component.ImplantedToSpeak.Count > 0) + { + foreach (var item in component.ImplantedToSpeak) + { + languageSpeaker.SpokenLanguages.Remove(item); + if (languageSpeaker.CurrentLanguage == item) + languageSpeaker.CurrentLanguage = languageSpeaker.SpokenLanguages.FirstOrDefault("Universal"); + } + } + + + component.ImplantedToUnderstand.Clear(); + component.ImplantedToSpeak.Clear(); + + Dirty(component.ImplantedEntity.Value, languageSpeaker); + + var menuEv = new LanguageMenuStateMessage(GetNetEntity(component.ImplantedEntity.Value), _language.GetCurrentLanguage(component.ImplantedEntity.Value).ID, languageSpeaker.UnderstoodLanguages); + RaiseNetworkEvent(menuEv); + + component.ImplantedEntity = null; + } + +} diff --git a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplanterSystem.cs b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplanterSystem.cs deleted file mode 100644 index 5a602d03c54..00000000000 --- a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplanterSystem.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Content.Shared.Examine; -using Content.Shared.Implants.Components; -using Content.Shared.Language.Components; -using Robust.Shared.Serialization; - -namespace Content.Shared.Language.Systems; - -public abstract class SharedTranslatorImplanterSystem : EntitySystem -{ - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnExamined); - } - - private void OnExamined(EntityUid uid, TranslatorImplanterComponent component, ExaminedEvent args) - { - if (!args.IsInDetailsRange) - return; - - var text = !component.Used - ? Loc.GetString("translator-implanter-ready") - : Loc.GetString("translator-implanter-used"); - - args.PushText(text); - } - - protected void OnAppearanceChange(EntityUid implanter, TranslatorImplanterComponent component) - { - var used = component.Used; - _appearance.SetData(implanter, ImplanterVisuals.Full, !used); - } -} diff --git a/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs b/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs index 540744139da..1cb350a658c 100644 --- a/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs @@ -1,8 +1,7 @@ -using Content.Shared.Examine; -using Content.Shared.Language.Components; +using Content.Shared.Examine; using Content.Shared.Toggleable; -namespace Content.Shared.Language.Systems; +namespace Content.Shared.Language; public abstract class SharedTranslatorSystem : EntitySystem { diff --git a/Content.Shared/Corvax/TTS/PlayTTSEvent.cs b/Content.Shared/Corvax/TTS/PlayTTSEvent.cs index 5b4db477c56..24aab224d1c 100644 --- a/Content.Shared/Corvax/TTS/PlayTTSEvent.cs +++ b/Content.Shared/Corvax/TTS/PlayTTSEvent.cs @@ -1,4 +1,5 @@ -using Robust.Shared.Serialization; +using Content.Shared.Language; +using Robust.Shared.Serialization; namespace Content.Shared.Corvax.TTS; @@ -7,13 +8,16 @@ namespace Content.Shared.Corvax.TTS; public sealed class PlayTTSEvent : EntityEventArgs { public byte[] Data { get; } + public byte[] LanguageData { get; } public NetEntity? SourceUid { get; } public bool IsWhisper { get; } - - public PlayTTSEvent(byte[] data, NetEntity? sourceUid = null, bool isWhisper = false) + public string LanguageProtoId { get; } + public PlayTTSEvent(byte[] data, byte[] languageData, LanguagePrototype language, NetEntity? sourceUid = null, bool isWhisper = false) { Data = data; SourceUid = sourceUid; IsWhisper = isWhisper; + LanguageProtoId = language.ID; + LanguageData = languageData; } } diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index 2dd671816fd..a9fa40de97f 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -26,6 +26,7 @@ public static class ContentKeyFunctions public static readonly BoundKeyFunction EscapeContext = "EscapeContext"; public static readonly BoundKeyFunction OpenCharacterMenu = "OpenCharacterMenu"; public static readonly BoundKeyFunction OpenEmotesMenu = "OpenEmotesMenu"; + public static readonly BoundKeyFunction OpenLanguagesMenu = "OpenLanguagesMenu"; // Languaжes public static readonly BoundKeyFunction OpenCraftingMenu = "OpenCraftingMenu"; public static readonly BoundKeyFunction OpenGuidebook = "OpenGuidebook"; public static readonly BoundKeyFunction OpenInventoryMenu = "OpenInventoryMenu"; diff --git a/Content.Shared/Radio/RadioChannelPrototype.cs b/Content.Shared/Radio/RadioChannelPrototype.cs index 166db0577ea..254d706490f 100644 --- a/Content.Shared/Radio/RadioChannelPrototype.cs +++ b/Content.Shared/Radio/RadioChannelPrototype.cs @@ -9,7 +9,7 @@ public sealed partial class RadioChannelPrototype : IPrototype /// Human-readable name for the channel. /// [DataField("name")] - public LocId Name { get; private set; } = string.Empty; + public string Name { get; private set; } = string.Empty; [ViewVariables(VVAccess.ReadOnly)] public string LocalizedName => Loc.GetString(Name); @@ -35,4 +35,9 @@ public sealed partial class RadioChannelPrototype : IPrototype /// [DataField("longRange"), ViewVariables] public bool LongRange = false; + + // Lang start + [DataField("translate"), ViewVariables] + public bool TranslateSpeech = false; + // Lang end } diff --git a/Resources/Locale/ru-RU/ADT/Languages/languages.ftl b/Resources/Locale/ru-RU/ADT/Languages/languages.ftl index f1cdbe6c926..5e8317f1bad 100644 --- a/Resources/Locale/ru-RU/ADT/Languages/languages.ftl +++ b/Resources/Locale/ru-RU/ADT/Languages/languages.ftl @@ -1,17 +1,24 @@ language-Universal-name = Универсальный -language-Universal-description = Что ты такое? +language-Universal-description = ЧТО ТЫ ТАКОЕ. + language-GalacticCommon-name = Общегалактический language-GalacticCommon-description = Обычно используется для межвидового общения и официальных целей. + language-Bubblish-name = Пузырчатый language-Bubblish-description = Язык слаймолюдов. Это смесь булькающих звуков и хлюпов. Человеку очень трудно говорить без механической помощи. + language-RootSpeak-name = Песнь корней language-RootSpeak-description = Странный шелестящий язык, на котором говорят дионы. + language-CodeSpeak-name = Кодовый язык language-CodeSpeak-description = Оперативники синдиката могут использовать серию кодовых слов для передачи сложной информации, в то время как для любого слушателя они звучат как случайные понятия и напитки. + language-Nekomimetic-name = Некоязык language-Nekomimetic-description = Для стороннего наблюдателя этот язык представляет собой непонятную смесь ломаного японского. Для фелинидов он каким-то образом понятен. + language-Draconic-name = Синта'унати language-Draconic-description = Общий язык унатхов с преобладающими шипящими звуками. + language-Canilunzt-name = Канилунц language-Canilunzt-description = Гортанный язык, на котором говорят и используют обитатели системы Ваззенда, состоящий из рычания, лая, тявканья и интенсивного использования движений ушей и хвоста, вулпканины говорят на этом языке с легкостью. @@ -26,6 +33,7 @@ language-Fire-description = Звуки огня, что каким-то обра language-SolCommon-name = Солнечный язык language-SolCommon-description = Общий язык, на котором говорят обитатели солнечной системы. + language-Cat-name = Кошачий language-Cat-description = Примитивные звуки, издаваемые кошками. Каким-то образом они передают смысл! @@ -87,7 +95,7 @@ language-Arkane-description = Протяжный, чем-то напоминаю language-Shadowkin-name = Миар language-Shadowkin-description = Загадочный язык, на котором говорят сумеречники. -language-Dwarf-name = Шахтёрский +language-Dwarf-name = Шахт language-Dwarf-description = Rock and stone! language-Dev-name = Разработческий @@ -95,39 +103,3 @@ language-Dev-description = Больше звучит как ругань пок language-CintaTaj-name = Синта’Тайр language-CintaTaj-description = Язык, разработанный таярами и унатхами для общения между двумя расами, представляет собой смесь шипений и слов. - -language-GalacticCommon = Общ. -language-Bubblish = Пузырчатый -language-RootSpeak = Песнь корней -language-CodeSpeak = Кодовый -language-Nekomimetic = Неко -language-Draconic = Синта'унати -language-Canilunzt = Канилунц -language-SikTaj = Сик'тайр -language-Nian = Ткачий -language-Fire = Огненный -language-SolCommon = Солнечный -language-Cat = Кошачий -language-Dog = Собачий -language-Mothroach = Молиный -language-Xeno = Ксено -language-RobotTalk = Троичный -language-Monkey = Обезьяний -language-Bee = Пчелиный -language-Mouse = Мышиный -language-Drask = Орлуум -# These ones are half-assed because these creatures are almost never played as. -language-Chicken = Animal chicken -language-Duck = Animal duck -language-Cow = Animal cow -language-Sheep = Animal sheep -language-Kangaroo = Animal kangaroo -language-Pig = Animal pig -language-Moffic = Паучий -language-BorgTalk = Двоичный -language-Urs = Рыкрур -language-Arkane = Каукиттен -language-Shadowkin = Миар -language-Dev = Разраб -language-Dwarf = Шахт -language-CintaTaj = Синта’тайр diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Actions/language-menu.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Actions/language-menu.ftl index 56833276de6..d4265c8e797 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Actions/language-menu.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Actions/language-menu.ftl @@ -1,6 +1,10 @@ language-menu-window-title = Выбор языка language-menu-current-language = Выбранный язык: {$language} language-menu-description-header = Описание -choose-lang-button = Выбрать +language-choose-button = Выбрать +language-choose-button-chosen = Выбрано +language-choose-button-cannot = Только понимание language-menu-action = Меню языков language-menu-action-desc = Открыть меню выбора языка. + +game-hud-open-languages-menu-button-tooltip = Открыть меню выбора языка diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/translators.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/translators.ftl index 5ae89edec38..4a6a944c6c4 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/translators.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/translators.ftl @@ -59,3 +59,13 @@ ent-NianTranslator = переводчик Ткачьего языка ent-FireTranslator = переводчик Огненного языка .desc = Используется для взаимного перевода Общегалактического и Огненного языков. + +ent-UrsTranslator = переводчик Рыкрур + .desc = Используется для взаимного перевода Общегалактического языка и Рыкрур. + +ent-IPCTranslator = переводчик троичного кода + .desc = Используется для взаимного перевода Общегалактического языка и троичного кода. + +ent-DwarfTranslator = переводчик языка Шахт + .desc = Используется для взаимного перевода Общегалактического языка и Шахт. + diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Misc/implanters.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Misc/implanters.ftl index ae8e374fb57..49672aa2322 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Misc/implanters.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Misc/implanters.ftl @@ -3,10 +3,7 @@ translator-implanter-success = {$implanter} успешно имплантиро translator-implanter-ready = Имплантер готов к использованию. translator-implanter-used = Имплантер пуст. -ent-BasicGalaticCommonTranslatorImplanter = базовый языковой имплант Общегалактического языка - .desc = Имплант, позволяющий понимать Общегалактический язык. - -ent-AdvancedGalaticCommonTranslatorImplanter = полноценный языковой имплант Общегалактического языка +ent-GalaticCommonTranslatorImplanter = полноценный языковой имплант Общегалактического языка .desc = Имплант, позволяющий понимать и общаться на Общегалактическом языке. ent-BubblishTranslatorImplanter = полноценный языковой имплант Пузырчатого языка @@ -60,6 +57,12 @@ ent-ShadowkinTranslatorImplanter = полноценный языковой им ent-BorgTranslatorImplanter = полноценный языковой имплант двоичного кода .desc = Имплант, позволяющий понимать и общаться на двоичном коде. +ent-DwarfTranslatorImplanter = полноценный языковой имплант Шахт + .desc = Имплант, позволяющий понимать и общаться на языке Шахт. + +ent-ArachnidTranslatorImplanter = полноценный языковой имплант Паучьего языка + .desc = Имплант, позволяющий понимать и общаться на языке арахнидов. + ent-SyndUniversalTranslatorImplanter = универсальный языковой имплант .desc = Имплант, позволяющий (только) понимать все расовые языки. diff --git a/Resources/Prototypes/ADT/Actions/language.yml b/Resources/Prototypes/ADT/Actions/language.yml deleted file mode 100644 index 222a73c9ba0..00000000000 --- a/Resources/Prototypes/ADT/Actions/language.yml +++ /dev/null @@ -1,12 +0,0 @@ -- type: entity - id: ActionLanguageMenu - name: language-menu-action - description: language-menu-action-desc - noSpawn: true - components: - - type: InstantAction - checkCanInteract: false - icon: _NF/Interface/Actions/language.png - event: !type:LanguageMenuActionEvent - useDelay: 2 - priority: -97 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml new file mode 100644 index 00000000000..c10fea2ec9e --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml @@ -0,0 +1,341 @@ +- type: entity + id: TranslatorUnpowered + parent: [ BaseItem ] + name: Translator + description: "Translates speech." + components: + - type: Sprite + sprite: ADT/Objects/Devices/translator.rsi + state: icon + layers: + - state: icon + - state: translator + shader: unshaded + visible: false + map: [ "enum.ToggleVisuals.Layer", "enum.PowerDeviceVisualLayers.Powered" ] + - type: Appearance + - type: GenericVisualizer + visuals: + enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Layer: + True: { visible: true } + False: { visible: false } + - type: HandheldTranslator + toSpeak: + - GalacticCommon + toUnderstand: + - GalacticCommon + enabled: false + +- type: entity + id: Translator + parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] + suffix: Powered + components: + - type: PowerCellDraw + drawRate: 0.5 + +- type: entity + id: TranslatorEmtpy + parent: [ Translator ] + suffix: Empty + components: + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + +- type: entity + id: BubblishTranslator + parent: [ Translator ] + name: Bubblish translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Bubblish + toUnderstand: + - GalacticCommon + - Bubblish + - type: StaticPrice + price: 1500 + +- type: entity + id: MofficTranslator + parent: [ Translator ] + name: Moffic translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Moffic + toUnderstand: + - GalacticCommon + - Moffic + - type: StaticPrice + price: 1500 + +- type: entity + id: RootSpeakTranslator + parent: [ Translator ] + name: RootSpeak translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - RootSpeak + toUnderstand: + - GalacticCommon + - RootSpeak + - type: StaticPrice + price: 1500 + +- type: entity + id: NekomimeticTranslator + parent: [ Translator ] + name: Nekomimetic translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Nekomimetic + toUnderstand: + - GalacticCommon + - Nekomimetic + - type: StaticPrice + price: 1500 + +- type: entity + id: DraconicTranslator + parent: [ Translator ] + name: Draconic translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Draconic + toUnderstand: + - GalacticCommon + - Draconic + - type: StaticPrice + price: 1500 + +- type: entity + id: CanilunztTranslator + parent: [ Translator ] + name: Canilunzt translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Canilunzt + toUnderstand: + - GalacticCommon + - Canilunzt + - type: StaticPrice + price: 1500 + +- type: entity + id: IPCTranslator + parent: [ Translator ] + name: IPC translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - RobotTalk + toUnderstand: + - GalacticCommon + - RobotTalk + - type: StaticPrice + price: 1500 + +- type: entity + id: FireTranslator + parent: [ Translator ] + name: Fire translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Fire + toUnderstand: + - GalacticCommon + - Fire + - type: StaticPrice + price: 1500 + +- type: entity + id: SolCommonTranslator + parent: [ Translator ] + name: SolCommon translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - SolCommon + toUnderstand: + - GalacticCommon + - SolCommon + - type: StaticPrice + price: 1500 + +- type: entity + id: ArachnidTranslator + parent: [ Translator ] + name: Arachnid translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Moffic + toUnderstand: + - GalacticCommon + - Moffic + - type: StaticPrice + price: 1500 + +- type: entity + id: DraskTranslator + parent: [ Translator ] + name: Drask translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Drask + toUnderstand: + - GalacticCommon + - Drask + - type: StaticPrice + price: 1500 + +- type: entity + id: UrsTranslator + parent: [ Translator ] + name: Urs translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Urs + toUnderstand: + - GalacticCommon + - Urs + - type: StaticPrice + price: 1500 + +- type: entity + id: ArkaneTranslator + parent: [ Translator ] + name: Arkane translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Arkane + toUnderstand: + - GalacticCommon + - Arkane + - type: StaticPrice + price: 1500 + +- type: entity + id: ShadowkinTranslator + parent: [ Translator ] + name: Shadowkin translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Shadowkin + toUnderstand: + - GalacticCommon + - Shadowkin + - type: StaticPrice + price: 1500 + +- type: entity + id: DwarfTranslator + parent: [ Translator ] + name: Dwarf translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Dwarf + toUnderstand: + - GalacticCommon + - Dwarf + - type: StaticPrice + price: 1500 + +- type: entity + id: CintaTajTranslator + parent: [ Translator ] + name: CintaTaj translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - CintaTaj + toUnderstand: + - GalacticCommon + - CintaTaj + - type: StaticPrice + price: 1500 + +- type: entity + id: AnimalTranslator + parent: [ Translator ] + name: Animals translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Cat + - Dog + - Mothroach + - Monkey + - Bee + - Mouse + - Chicken + - Duck + - Cow + - Sheep + - Kangaroo + - Pig + toUnderstand: + - GalacticCommon + - Cat + - Dog + - Mothroach + - Mothroach + - Monkey + - Bee + - Mouse + - Chicken + - Duck + - Cow + - Sheep + - Kangaroo + - Pig + - type: StaticPrice + price: 1500 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml new file mode 100644 index 00000000000..d2b3926f675 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml @@ -0,0 +1,167 @@ +- type: entity + id: GalacticCommonTranslatorImplanter + name: Galactic Common Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: GalacticCommonTranslatorImplant + +- type: entity + id: BubblishTranslatorImplanter + name: Bubblish Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: BubblishTranslatorImplant + +- type: entity + id: MofficTranslatorImplanter + name: Moffic Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: MofficTranslatorImplant + +- type: entity + id: RootSpeakTranslatorImplanter + name: RootSpeak Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: RootSpeakTranslatorImplant + +- type: entity + id: NekomimeticTranslatorImplanter + name: Nekomimetic Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: NekomimeticTranslatorImplant + +- type: entity + id: DraconicTranslatorImplanter + name: Draconic Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: DraconicTranslatorImplant + +- type: entity + id: CanilunztTranslatorImplanter + name: Canilunzt Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: CanilunztTranslatorImplant + +- type: entity + id: IPCTranslatorImplanter + name: IPC Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: IPCTranslatorImplant + +- type: entity + id: BorgTranslatorImplanter + name: Borg Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: BorgTranslatorImplant + +- type: entity + id: ArachnidTranslatorImplanter + name: Arachnid Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: ArachnidTranslatorImplant + +- type: entity + id: FireTranslatorImplanter + name: Fire Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: FireTranslatorImplant + +- type: entity + id: SolCommonTranslatorImplanter + name: SolCommon Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: SolCommonTranslatorImplant + +- type: entity + id: DraskTranslatorImplanter + name: Drask Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: DraskTranslatorImplant + +- type: entity + id: UrsTranslatorImplanter + name: Urs Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: UrsTranslatorImplant + +- type: entity + id: ArkaneTranslatorImplanter + name: Arkane Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: ArkaneTranslatorImplant + +- type: entity + id: ShadowkinTranslatorImplanter + name: Shadowkin Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: ShadowkinTranslatorImplant + +- type: entity + id: DwarfTranslatorImplanter + name: Dwarf Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: DwarfTranslatorImplant + +- type: entity + id: CintaTajTranslatorImplanter + name: CintaTaj Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: CintaTajTranslatorImplant + +- type: entity + id: CodeSpeakImplanter + name: Code speak Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: CodeSpeakTranslatorImplant + +- type: entity + id: SyndUniversalTranslatorImplanter + name: Universal Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: SyndUniversalTranslatorImplant + +- type: entity + id: DevTranslatorImplanter + name: Dev Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: DevTranslatorImplant diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml new file mode 100644 index 00000000000..d832df07bd9 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml @@ -0,0 +1,297 @@ +- type: entity + id: BaseTranslatorImplant + abstract: true + components: + - type: SubdermalImplant + - type: Tag + tags: + - SubdermalImplant + - HideContextMenu + +- type: entity + parent: BaseTranslatorImplant + id: GalacticCommonTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - GalacticCommon + toUnderstand: + - GalacticCommon + +- type: entity + parent: BaseTranslatorImplant + id: BubblishTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Bubblish + toUnderstand: + - Bubblish + +- type: entity + parent: BaseTranslatorImplant + id: MofficTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Nian + toUnderstand: + - Nian + +- type: entity + parent: BaseTranslatorImplant + id: RootSpeakTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant +# toSpeak: +# - RootSpeak # Никто кроме дион не может шуршать ветками, когда их нет, даже с имплантом + toUnderstand: + - RootSpeak + +- type: entity + parent: BaseTranslatorImplant + id: NekomimeticTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Nekomimetic + toUnderstand: + - Nekomimetic + +- type: entity + parent: BaseTranslatorImplant + id: DraconicTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Draconic + toUnderstand: + - Draconic + +- type: entity + parent: BaseTranslatorImplant + id: CanilunztTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Canilunzt + toUnderstand: + - Canilunzt + +- type: entity + parent: BaseTranslatorImplant + id: IPCTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - RobotTalk + toUnderstand: + - RobotTalk + +- type: entity + parent: BaseTranslatorImplant + id: BorgTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - BorgTalk + toUnderstand: + - BorgTalk + +- type: entity + parent: BaseTranslatorImplant + id: ArachnidTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Moffic + toUnderstand: + - Moffic + +- type: entity + parent: BaseTranslatorImplant + id: FireTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant +# toSpeak: +# - Fire # как с дионами + toUnderstand: + - Fire + +- type: entity + parent: BaseTranslatorImplant + id: SolCommonTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - SolCommon + toUnderstand: + - SolCommon + +- type: entity + parent: BaseTranslatorImplant + id: DraskTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Drask + toUnderstand: + - Drask + +- type: entity + parent: BaseTranslatorImplant + id: UrsTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Urs + toUnderstand: + - Urs + +- type: entity + parent: BaseTranslatorImplant + id: ArkaneTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Arkane + toUnderstand: + - Arkane + +- type: entity + parent: BaseTranslatorImplant + id: ShadowkinTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Shadowkin + toUnderstand: + - Shadowkin + +- type: entity + parent: BaseTranslatorImplant + id: DwarfTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Dwarf + toUnderstand: + - Dwarf + +- type: entity + parent: BaseTranslatorImplant + id: CintaTajTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - CintaTaj + toUnderstand: + - CintaTaj + +- type: entity + parent: BaseTranslatorImplant + id: SyndUniversalTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toUnderstand: + - RobotTalk + - Shadowkin + - Arkane + - Urs + - Drask + - Fire + - Nian + - SikTaj + - Moffic + - RootSpeak + - SolCommon + - Canilunzt + - Draconic + - Bubblish + - Nekomimetic + - BorgTalk + - Dwarf + - CintaTaj + +- type: entity + parent: BaseTranslatorImplant + id: CodeSpeakTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - CodeSpeak + toUnderstand: + - CodeSpeak + +- type: entity + parent: BaseTranslatorImplant + id: DevTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Dev + toUnderstand: + - Dev diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/translators.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/translators.yml deleted file mode 100644 index 76929a0b173..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/translators.yml +++ /dev/null @@ -1,388 +0,0 @@ -- type: entity - id: TranslatorUnpowered - parent: [ BaseItem ] - name: Translator - description: "Translates speech." - components: - - type: Item - sprite: _NF/Objects/Devices/translator.rsi - inhandVisuals: - left: - - state: inhand-left - right: - - state: inhand-right - - type: Sprite - sprite: _NF/Objects/Devices/translator.rsi - state: icon - layers: - - state: icon - - state: translator - shader: unshaded - visible: false - map: [ "enum.ToggleVisuals.Layer", "enum.PowerDeviceVisualLayers.Powered" ] - - type: Appearance - - type: GenericVisualizer - visuals: - enum.ToggleVisuals.Toggled: - enum.ToggleVisuals.Layer: - True: { visible: true } - False: { visible: false } - - type: HandheldTranslator - enabled: false - - type: ToggleableLightVisuals - spriteLayer: translator - inhandVisuals: - left: - - state: inhand-left-translator - shader: unshaded - right: - - state: inhand-right-translator - shader: unshaded - -- type: entity - id: Translator - parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] - suffix: Powered - components: - - type: PowerCellDraw - drawRate: 1 - - type: ItemToggle - onUse: false # above component does the toggling - -- type: entity - id: TranslatorEmtpy - parent: [ Translator ] - suffix: Empty - components: - - type: ItemSlots - slots: - cell_slot: - name: power-cell-slot-component-slot-name-default - -- type: entity - id: VulpTranslator - parent: [ Translator ] - name: Vulpkanin translator - description: "Used only by Vulpkanin to understand and speak with Galatic Common speakers." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - understood: - - GalacticCommon - requires: - - Canilunzt - requires-all: false - - type: PowerCellDraw - drawRate: 0.1 - - type: StaticPrice - price: 35 - -- type: entity - id: CanilunztTranslator - parent: [ TranslatorEmtpy ] - name: Canilunzt translator - description: "Translates speech between Canilunzt and Galactic Common. Commonly used by Vulpkanin to communicate with galactic common speakers" - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Canilunzt - understood: - - GalacticCommon - - Canilunzt - requires: - - GalacticCommon - - Canilunzt - requires-all: false - -- type: entity - id: BubblishTranslator - parent: [ TranslatorEmtpy ] - name: Bubblish translator - description: "Translates speech between Bubblish and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Bubblish - understood: - - GalacticCommon - - Bubblish - requires: - - GalacticCommon - - Bubblish - requires-all: false - -- type: entity - id: NekomimeticTranslator - parent: [ TranslatorEmtpy ] - name: Nekomimetic translator - description: "Translates speech between Nekomimetic and Galactic Common. Why would you want that?" - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Nekomimetic - understood: - - GalacticCommon - - Nekomimetic - requires: - - GalacticCommon - - Nekomimetic - requires-all: false - -- type: entity - id: DraconicTranslator - parent: [ TranslatorEmtpy ] - name: Draconic translator - description: "Translates speech between Draconic and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Draconic - understood: - - GalacticCommon - - Draconic - requires: - - GalacticCommon - - Draconic - requires-all: false - -- type: entity - id: SolCommonTranslator - parent: [ TranslatorEmtpy ] - name: Sol Common translator - description: "Translates speech between Sol Common and Galactic Common. Like a true Earthman!" - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - SolCommon - understood: - - GalacticCommon - - SolCommon - requires: - - GalacticCommon - - SolCommon - requires-all: false - -- type: entity - id: RootSpeakTranslator - parent: [ TranslatorEmtpy ] - name: RootSpeak translator - description: "Translates speech between RootSpeak and Galactic Common. Like a true plant?" - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - RootSpeak - understood: - - GalacticCommon - - RootSpeak - requires: - - GalacticCommon - - RootSpeak - requires-all: false - -- type: entity - id: MofficTranslator - parent: [ TranslatorEmtpy ] - name: Moffic translator - description: "Translates speech between Moffic and Galactic Common. Like a true moth... or bug?" - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Moffic - understood: - - GalacticCommon - - Moffic - requires: - - GalacticCommon - - Moffic - requires-all: false - -- type: entity - id: XenoTranslator - parent: [ TranslatorEmtpy ] - name: Xeno translator - description: "Translates speech between Xeno and Galactic Common. Not sure if that will help." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Xeno - understood: - - GalacticCommon - - Xeno - requires: - - GalacticCommon - -- type: entity - id: AnimalTranslator - parent: [ TranslatorEmtpy ] - name: Animal translator - description: "Translates all the cutes nosies that animals make into a more understandable form!" - components: - - type: HandheldTranslator - understood: - - Cat - - Dog - - Mothroach - - Monkey - - Bee - - Mouse - - Chicken - - Duck - - Cow - - Sheep - - Kangaroo - - Pig - requires: - - GalacticCommon - requires-all: false - -- type: entity - id: DraskTranslator - parent: [ TranslatorEmtpy ] - name: Orluum translator - description: "Translates speech between Orluum and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Drask - understood: - - GalacticCommon - - Drask - requires: - - GalacticCommon - - Drask - requires-all: false - - -- type: entity - id: ShadowkinTranslator - parent: [ TranslatorEmtpy ] - name: Shadowkin translator - description: "Translates speech between Shadowkin lang and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Shadowkin - understood: - - GalacticCommon - - Shadowkin - requires: - - GalacticCommon - - Shadowkin - requires-all: false - -- type: entity - id: ArkaneTranslator - parent: [ TranslatorEmtpy ] - name: Arkane translator - description: "Translates speech between Arkane lang and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Arkane - understood: - - GalacticCommon - - Arkane - requires: - - GalacticCommon - - Arkane - requires-all: false - -- type: entity - id: NianTranslator - parent: [ TranslatorEmtpy ] - name: Nian translator - description: "Translates speech between Nian lang and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Nian - understood: - - GalacticCommon - - Nian - requires: - - GalacticCommon - - Nian - requires-all: false - -- type: entity - id: FireTranslator - parent: [ TranslatorEmtpy ] - name: Fire translator - description: "Translates speech between Shadowkin lang and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - Fire - understood: - - GalacticCommon - - Fire - requires: - - GalacticCommon - - Fire - requires-all: false - -- type: entity - id: SikTajTranslator - parent: [ TranslatorEmtpy ] - name: SikTaj translator - description: "Translates speech between SikTaj and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - SikTaj - understood: - - GalacticCommon - - SikTaj - requires: - - GalacticCommon - - SikTaj - requires-all: false - -- type: entity - id: CintaTajTranslator - parent: [ TranslatorEmtpy ] - name: CintaTajTaj translator - description: "Translates speech between CintaTaj and Galactic Common." - components: - - type: HandheldTranslator - default-language: GalacticCommon - spoken: - - GalacticCommon - - CintaTaj - understood: - - GalacticCommon - - CintaTaj - requires: - - GalacticCommon - - CintaTaj - requires-all: false diff --git a/Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml b/Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml deleted file mode 100644 index 3ebd7c90366..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml +++ /dev/null @@ -1,287 +0,0 @@ -- type: entity - id: BaseTranslatorImplanter - parent: [ BaseItem ] - name: Basic translator implant - description: "Translates speech." - abstract: true - components: - - type: Sprite - sprite: Objects/Specific/Medical/implanter.rsi - state: implanter0 - layers: - - state: implanter1 - map: [ "implantFull" ] - visible: true - - state: implanter0 - map: [ "implantBroken" ] - - type: Appearance - - type: GenericVisualizer - visuals: - enum.ImplanterVisuals.Full: - implantFull: - True: {visible: true} - False: {visible: false} - implantBroken: - True: {visible: false} - False: {visible: true} - -- type: entity - id: BasicGalaticCommonTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Basic Galatic Common translator implant - description: "An implant giving the ability to understand Galatic Common." - components: - - type: TranslatorImplanter - understood: - - GalacticCommon - -- type: entity - id: AdvancedGalaticCommonTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Advanced Galatic Common translator implant - description: "An implant giving the ability to understand and speak Galatic Common." - components: - - type: TranslatorImplanter - spoken: - - GalacticCommon - understood: - - GalacticCommon - -- type: entity - id: BubblishTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Bubblish translator implant - description: "An implant giving the ability to understand and speak Bubblish." - components: - - type: TranslatorImplanter - spoken: - - Bubblish - understood: - - Bubblish - -- type: entity - id: NekomimeticTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Nekomimetic translator implant - description: "An implant giving the ability to understand and speak Nekomimetic, Nya~!" - components: - - type: TranslatorImplanter - spoken: - - Nekomimetic - understood: - - Nekomimetic - -- type: entity - id: DraconicTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Draconic translator implant - description: "An implant giving the ability to understand and speak Draconic." - components: - - type: TranslatorImplanter - spoken: - - Draconic - understood: - - Draconic - -- type: entity - id: CanilunztTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Canilunzt translator implant - description: "An implant giving the ability to understand and speak Canilunzt, Yeeps!" - components: - - type: TranslatorImplanter - spoken: - - Canilunzt - understood: - - Canilunzt - -- type: entity - id: SolCommonTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: SolCommon translator implant - description: "An implant giving the ability to understand and speak SolCommon, raaagh!" - components: - - type: TranslatorImplanter - spoken: - - SolCommon - understood: - - SolCommon - -- type: entity - id: RootSpeakTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: RootSpeak translator implant - description: "An implant giving the ability to understand and speak RootSpeak." - components: - - type: TranslatorImplanter - understood: - - RootSpeak - -- type: entity - id: MofficTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Moffic translator implant - description: "An implant giving the ability to understand and speak Moffic." - components: - - type: TranslatorImplanter - spoken: - - Moffic - understood: - - Moffic - -- type: entity - id: CodeSpeakImplanter - parent: [ BaseTranslatorImplanter ] - name: CodeSpeak Implanter - description: "\"CodeSpeak(tm) - Secure your communication with metaphors so elaborate, they seem randomly generated!\"" - components: - - type: TranslatorImplanter - spoken: - - CodeSpeak - understood: - - CodeSpeak - - type: StaticPrice - price: 150 - -- type: entity - id: SikTajTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: SikTaj translator implant - description: "An implant giving the ability to understand and speak SikTaj." - components: - - type: TranslatorImplanter - spoken: - - SikTaj - understood: - - SikTaj - -- type: entity - id: NianTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Nian translator implant - description: "An implant giving the ability to understand and speak Nian." - components: - - type: TranslatorImplanter - spoken: - - Nian - understood: - - Nian - -- type: entity - id: FireTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Nian translator implant - description: "An implant giving the ability to understand and speak Nian." - components: - - type: TranslatorImplanter - understood: - - Fire - -- type: entity - id: DraskTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Orluum translator implant - description: "An implant giving the ability to understand and speak Orluum." - components: - - type: TranslatorImplanter - spoken: - - Drask - understood: - - Drask - -- type: entity - id: UrsTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Urs translator implant - description: "An implant giving the ability to understand and speak Ursus language." - components: - - type: TranslatorImplanter - spoken: - - Urs - understood: - - Urs - -- type: entity - id: ArkaneTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Arkane translator implant - description: "An implant giving the ability to understand and speak Arcane language." - components: - - type: TranslatorImplanter - spoken: - - Arkane - understood: - - Arkane - -- type: entity - id: ShadowkinTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Shadowkin translator implant - description: "An implant giving the ability to understand and speak Shadowkin language." - components: - - type: TranslatorImplanter - spoken: - - Shadowkin - understood: - - Shadowkin - -- type: entity - id: BorgTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Borg translator implant - description: "An implant giving the ability to understand and speak Binary." - components: - - type: TranslatorImplanter - spoken: - - BorgTalk - understood: - - BorgTalk - -- type: entity - id: CintaTajTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: CintaTaj translator implant - description: "An implant giving the ability to understand and speak CintaTaj." - components: - - type: TranslatorImplanter - spoken: - - CintaTaj - understood: - - CintaTaj - - -- type: entity - id: SyndUniversalTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: universal translator implant - description: "An implant giving the ability to understand any racial language." - components: - - type: TranslatorImplanter - understood: - - RobotTalk - - Shadowkin - - Arkane - - Urs - - Drask - - Fire - - Nian - - SikTaj - - Moffic - - RootSpeak - - SolCommon - - Canilunzt - - Draconic - - Bubblish - - Nekomimetic - -- type: entity - id: DevTranslatorImplanter - parent: [ BaseTranslatorImplanter ] - name: Dev translator implant - description: "e" - components: - - type: TranslatorImplanter - spoken: - - Dev - understood: - - Dev diff --git a/Resources/Prototypes/ADT/Languages/languages.yml b/Resources/Prototypes/ADT/Languages/languages.yml index 10dde690b5b..480c4d57a4d 100644 --- a/Resources/Prototypes/ADT/Languages/languages.yml +++ b/Resources/Prototypes/ADT/Languages/languages.yml @@ -11,9 +11,9 @@ id: GalacticCommon obfuscateSyllables: true replacement: - - Бла - - Бла - - Бла + - бла + - бла + - бла - динг-донг - динг - донг @@ -35,6 +35,8 @@ - type: language id: Bubblish obfuscateSyllables: true + color: "#61daff" + whisperColor: "#5f9db0" replacement: - блоб - плоп @@ -49,6 +51,8 @@ - type: language id: Moffic obfuscateSyllables: true + color: "#b34444" + whisperColor: "#8a4343" replacement: - år - i @@ -112,6 +116,8 @@ - type: language id: RootSpeak obfuscateSyllables: true + color: "#76ff61" + whisperColor: "#7fc474" replacement: - хс - зт @@ -124,6 +130,8 @@ - type: language id: CodeSpeak obfuscateSyllables: true + color: Crimson + whisperColor: Crimson replacement: - Белый русский - Представитель станции @@ -179,6 +187,8 @@ - type: language id: Nekomimetic obfuscateSyllables: true + color: "#ff78e8" + whisperColor: "#c280b7" replacement: - неко - нян @@ -233,6 +243,8 @@ - type: language id: Draconic obfuscateSyllables: true + color: "#0ea600" + whisperColor: "#31702c" replacement: - za - az @@ -323,6 +335,8 @@ - type: language id: Canilunzt obfuscateSyllables: true + color: "#ff9a3b" + whisperColor: "#cf8f53" replacement: - rur - ya @@ -387,6 +401,8 @@ - type: language id: SikTaj obfuscateSyllables: true + color: "#ff683b" + whisperColor: "#cf7b61" replacement: - rae - ye @@ -451,6 +467,8 @@ - type: language id: Nian obfuscateSyllables: true + color: "#ffdd61" + whisperColor: "#cfb96b" replacement: - жз - эзз @@ -485,6 +503,8 @@ - type: language id: Fire obfuscateSyllables: true + color: "#ff6a00" + whisperColor: "#e0894a" replacement: - шш - вшш @@ -501,6 +521,8 @@ - type: language id: SolCommon obfuscateSyllables: true + color: "#00fc65" + whisperColor: "#6db389" replacement: - тао - ши @@ -562,6 +584,8 @@ - type: language id: RobotTalk obfuscateSyllables: true + color: "#5773ff" + whisperColor: "#7c8acc" replacement: - "0" - "1" @@ -570,6 +594,8 @@ - type: language id: BorgTalk obfuscateSyllables: true + color: "#9faffc" + whisperColor: "#babfd6" replacement: - "0" - "1" @@ -650,6 +676,8 @@ - type: language id: Drask obfuscateSyllables: true + color: "#0074c7" + whisperColor: "#538cb5" replacement: - овв - оумн @@ -673,6 +701,8 @@ - type: language id: Urs obfuscateSyllables: true + color: "#b36b00" + whisperColor: "#99743d" replacement: - раа - ишш @@ -702,6 +732,8 @@ - type: language id: Arkane obfuscateSyllables: true + color: "#e478ff" + whisperColor: "#c79fd1" replacement: - рииа - инн @@ -725,6 +757,8 @@ - type: language id: Shadowkin obfuscateSyllables: true + color: "#c048f7" + whisperColor: "#a68bb3" replacement: - mia - ar @@ -748,6 +782,8 @@ - type: language id: Dwarf obfuscateSyllables: true + color: "#f5e238" + whisperColor: "#d4cb79" replacement: - арр - рок @@ -770,6 +806,8 @@ - type: language id: CintaTaj obfuscateSyllables: true + color: "#88d424" + whisperColor: "#91ba5b" replacement: - za - az @@ -918,6 +956,7 @@ - type: language id: Dev obfuscateSyllables: true + color: White replacement: - су - ка diff --git a/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml b/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml index 233acfe64dd..97664bc034f 100644 --- a/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml +++ b/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml @@ -69,8 +69,8 @@ Gold: 50 - type: latheRecipe - id: BasicGalaticCommonTranslatorImplanter - result: BasicGalaticCommonTranslatorImplanter + id: GalaticCommonTranslatorImplanter + result: GalaticCommonTranslatorImplanter completetime: 2 materials: Steel: 500 @@ -79,27 +79,16 @@ Gold: 50 Silver: 50 -- type: latheRecipe - id: XenoTranslator - result: XenoTranslator - completetime: 2 - materials: - Steel: 200 - Plastic: 50 - Gold: 50 - Plasma: 50 - Silver: 50 - -- type: latheRecipe - id: AdvancedGalaticCommonTranslatorImplanter - result: AdvancedGalaticCommonTranslatorImplanter - completetime: 2 - materials: - Steel: 500 - Glass: 500 - Plastic: 100 - Gold: 50 - Silver: 50 +#- type: latheRecipe +# id: XenoTranslator +# result: XenoTranslator +# completetime: 2 +# materials: +# Steel: 200 +# Plastic: 50 +# Gold: 50 +# Plasma: 50 +# Silver: 50 - type: latheRecipe id: BubblishTranslatorImplanter @@ -222,6 +211,17 @@ Gold: 50 Silver: 50 +- type: latheRecipe + id: DraskTranslatorImplanter + result: DraskTranslatorImplanter + completetime: 2 + materials: + Steel: 500 + Glass: 500 + Plastic: 100 + Gold: 50 + Silver: 50 + - type: latheRecipe id: DraskTranslator result: DraskTranslator @@ -233,15 +233,24 @@ Gold: 50 - type: latheRecipe - id: DraskTranslatorImplanter - result: DraskTranslatorImplanter + id: DwarfTranslator + result: DwarfTranslator completetime: 2 materials: Steel: 500 - Glass: 500 - Plastic: 100 + Glass: 100 + Plastic: 50 + Gold: 50 + +- type: latheRecipe + id: IPCTranslator + result: IPCTranslator + completetime: 2 + materials: + Steel: 500 + Glass: 100 + Plastic: 50 Gold: 50 - Silver: 50 - type: latheRecipe id: UrsTranslatorImplanter @@ -287,15 +296,15 @@ Gold: 50 Silver: 50 -#- type: latheRecipe -# id: UrsTranslator -# result: UrsTranslator -# completetime: 2 -# materials: -# Steel: 500 -# Glass: 100 -# Plastic: 50 -# Gold: 50 +- type: latheRecipe + id: UrsTranslator + result: UrsTranslator + completetime: 2 + materials: + Steel: 500 + Glass: 100 + Plastic: 50 + Gold: 50 - type: latheRecipe id: ArkaneTranslator diff --git a/Resources/Prototypes/ADT/Research/translators.yml b/Resources/Prototypes/ADT/Research/translators.yml index a687d06a53d..b88b16ee385 100644 --- a/Resources/Prototypes/ADT/Research/translators.yml +++ b/Resources/Prototypes/ADT/Research/translators.yml @@ -15,17 +15,18 @@ - DraconicTranslator - SolCommonTranslator - RootSpeakTranslator - - BasicGalaticCommonTranslatorImplanter + - GalaticCommonTranslatorImplanter - MofficTranslator - DraskTranslator -# - UrsTranslator # Закомменчено до раундстарт урсов + - UrsTranslator # Закомменчено до раундстарт урсов # И никто не раскомментил, молодцы - ArkaneTranslator - ShadowkinTranslator - NianTranslator - FireTranslator - SikTajTranslator - CintaTajTranslator - + - IPCTranslator + - DwarfTranslator # Frontier - languages mechanic - type: technology @@ -38,8 +39,8 @@ tier: 3 cost: 15000 recipeUnlocks: - - XenoTranslator - - AdvancedGalaticCommonTranslatorImplanter +# - XenoTranslator +# - AdvancedGalaticCommonTranslatorImplanter - BubblishTranslatorImplanter - NekomimeticTranslatorImplanter - DraconicTranslatorImplanter @@ -53,7 +54,10 @@ - NianTranslatorImplanter - FireTranslatorImplanter - DraskTranslatorImplanter -# - UrsTranslatorImplanter # Закомменчено до раундстарт урсов + - UrsTranslatorImplanter # Закомменчено до раундстарт урсов # И никто не раскомментил, молодцы - ArkaneTranslatorImplanter - ShadowkinTranslatorImplanter - CintaTajTranslatorImplanter + - IPCTranslatorImplanter + - BorgTranslatorImplanter + - DwarfTranslatorImplanter diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml index 0f826936a5c..4b95c52885d 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml @@ -48,7 +48,11 @@ - type: Tag tags: - BypassInteractionRangeChecks - - type: UniversalLanguageSpeaker # Frontier / Ghosts should understand any language. + - type: LanguageSpeaker + speaks: + - Universal + understands: + - Universal - type: entity id: ActionGhostBoo diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 87b672847de..ed016046968 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -333,17 +333,16 @@ - FauxTileAstroSnow - OreBagOfHolding - DeviceQuantumSpinInverter - # vv Frontier - languages mechanic vv + # vv Languages mechanic vv - CanilunztTranslator - BubblishTranslator - NekomimeticTranslator - DraconicTranslator - SolCommonTranslator - RootSpeakTranslator - - XenoTranslator + #- XenoTranslator - DraskTranslator - - BasicGalaticCommonTranslatorImplanter - - AdvancedGalaticCommonTranslatorImplanter + - GalaticCommonTranslatorImplanter - BubblishTranslatorImplanter - NekomimeticTranslatorImplanter - DraconicTranslatorImplanter @@ -357,18 +356,20 @@ - NianTranslatorImplanter - FireTranslatorImplanter - DraskTranslatorImplanter -# - UrsTranslatorImplanter # Закомменчено до раундстарт урсов + - UrsTranslatorImplanter - ArkaneTranslatorImplanter - ShadowkinTranslatorImplanter - CintaTajTranslatorImplanter -# - UrsTranslator # Закомменчено до раундстарт урсов + - UrsTranslator - ArkaneTranslator - ShadowkinTranslator - NianTranslator - FireTranslator - SikTajTranslator - CintaTajTranslator - # ^^ Frontier - languages mechanic ^^ + - DwarfTranslator + - IPCTranslator + # ^^ Languages mechanic ^^ - type: EmagLatheRecipes emagDynamicRecipes: - BoxBeanbag diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/icon.png b/Resources/Textures/ADT/Objects/Devices/translator.rsi/icon.png similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/icon.png rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/icon.png diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-left-translator.png b/Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-left-translator.png similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-left-translator.png rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-left-translator.png diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-left.png b/Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-left.png rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-left.png diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-right-translator.png b/Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-right-translator.png similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-right-translator.png rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-right-translator.png diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-right.png b/Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/inhand-right.png rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/inhand-right.png diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/meta.json b/Resources/Textures/ADT/Objects/Devices/translator.rsi/meta.json similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/meta.json rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/meta.json diff --git a/Resources/Textures/_NF/Objects/Devices/translator.rsi/translator.png b/Resources/Textures/ADT/Objects/Devices/translator.rsi/translator.png similarity index 100% rename from Resources/Textures/_NF/Objects/Devices/translator.rsi/translator.png rename to Resources/Textures/ADT/Objects/Devices/translator.rsi/translator.png diff --git a/Resources/Textures/Interface/languages-menu.svg b/Resources/Textures/Interface/languages-menu.svg new file mode 100644 index 00000000000..0dd1d100870 --- /dev/null +++ b/Resources/Textures/Interface/languages-menu.svg @@ -0,0 +1,7 @@ + + + + + + ic_fluent_translate_24_filled Created with Sketch. + \ No newline at end of file diff --git a/Resources/Textures/Interface/languages-menu.svg.192dpi.png b/Resources/Textures/Interface/languages-menu.svg.192dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..41a2e310ca0dd5abdecf1994498b8d67d130b30f GIT binary patch literal 804 zcmV+<1Ka$GP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0=Y>x#l5Hnp90bNi7$>3QB6KGKJ~dxiok+6mCSj%ez1Jt(u`TOQY&Ta)k|arz zBuSDa$s6YPD;qXl4mA9j%W(pXeH?5q;p6pz?x$f1CR=u$1z&^t^qO2#n#fEnc5@9_oG{1y4mVJ}V_9Vt2MCrE7IuK^eBmAC;=oQf690;b170Y{ zd=&2ZeJV0;V$SV<0tTO0h+hN z)4tQBDW!Uq91}@nsFD4^+5=o#Uz5-)AchO9u0faa0+!iy6|XvAWy3{Z==$t%+p=ai zU6wH3OHrt^j?Z2;P-op^_Lv!f#XPcDLlk_&@1$Ly&YshFq5t+N3$kDr7j%0VdYABV z0h-klV?<#L+d^=NO6xt~xpkKf@}1J7J3HV5Gn-WhSYCter*2Raph~?OdpPT}g7cYj zLTd&r!3WB@X!>*2;(#@;wl|a$YSD*K(;dUqFGMX4=)Rn^0wdJj+cG}LC&~iL0q)ru zkk$LG+Jah3BC4yP$mX(u_9)YEd1~8yyQP z5>O+Ttm=)>887X>hFXa=MyMWx9Nc^=cuFuKoZz0;9tcHy=&_0000 Date: Fri, 2 Aug 2024 09:25:15 +0400 Subject: [PATCH 02/15] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/Language/LanguagePrototype.cs | 3 -- .../Objects/Device/Translators/handheld.yml | 35 ++++++++++++++++++- .../Objects/Device/Translators/implanters.yml | 16 +++++++++ .../Objects/Device/Translators/implants.yml | 26 ++++++++++++++ .../ADT/Recipes/Lathes/translators.yml | 33 +++++++++++++++++ .../Prototypes/ADT/Research/translators.yml | 2 +- 6 files changed, 110 insertions(+), 5 deletions(-) diff --git a/Content.Shared/ADT/Language/LanguagePrototype.cs b/Content.Shared/ADT/Language/LanguagePrototype.cs index 8850ebc24c5..598b14f14cc 100644 --- a/Content.Shared/ADT/Language/LanguagePrototype.cs +++ b/Content.Shared/ADT/Language/LanguagePrototype.cs @@ -13,9 +13,6 @@ public sealed class LanguagePrototype : IPrototype [DataField("obfuscateSyllables")] public bool ObfuscateSyllables { get; private set; } = false; - [DataField("show")] - public bool ShowName { get; private set; } = true; - [DataField] public Color? Color; diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml index c10fea2ec9e..12ac3ee751b 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml @@ -26,7 +26,8 @@ toUnderstand: - GalacticCommon enabled: false - + - type: ItemToggle + - type: entity id: Translator parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] @@ -301,6 +302,38 @@ - type: StaticPrice price: 1500 +- type: entity + id: NianTranslator + parent: [ Translator ] + name: Nian translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - Nian + toUnderstand: + - GalacticCommon + - Nian + - type: StaticPrice + price: 1500 + +- type: entity + id: SikTajTranslator + parent: [ Translator ] + name: SikTaj translator + description: "Translates speech." + components: + - type: HandheldTranslator + toSpeak: + - GalacticCommon + - SikTaj + toUnderstand: + - GalacticCommon + - SikTaj + - type: StaticPrice + price: 1500 + - type: entity id: AnimalTranslator parent: [ Translator ] diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml index d2b3926f675..0500bf469c7 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml @@ -158,6 +158,22 @@ - type: Implanter implant: SyndUniversalTranslatorImplant +- type: entity + id: SikTajTranslatorImplanter + name: Universal Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: SikTajTranslatorImplant + +- type: entity + id: NianTranslatorImplanter + name: Universal Translator implanter + parent: BaseImplantOnlyImplanter + components: + - type: Implanter + implant: NianTranslatorImplant + - type: entity id: DevTranslatorImplanter name: Dev Translator implanter diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml index d832df07bd9..702dce1a09b 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml @@ -283,6 +283,32 @@ toUnderstand: - CodeSpeak +- type: entity + parent: BaseTranslatorImplant + id: SikTajTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - SikTaj + toUnderstand: + - SikTaj + +- type: entity + parent: BaseTranslatorImplant + id: NianTranslatorImplant + name: translator implant + description: This implant grants language knowledge. + noSpawn: true + components: + - type: TranslatorImplant + toSpeak: + - Nian + toUnderstand: + - Nian + - type: entity parent: BaseTranslatorImplant id: DevTranslatorImplant diff --git a/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml b/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml index 97664bc034f..55618550bbc 100644 --- a/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml +++ b/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml @@ -167,6 +167,39 @@ Gold: 50 Silver: 50 +- type: latheRecipe + id: IPCTranslatorImplanter + result: IPCTranslatorImplanter + completetime: 2 + materials: + Steel: 500 + Glass: 500 + Plastic: 100 + Gold: 50 + Silver: 50 + +- type: latheRecipe + id: BorgTranslatorImplanter + result: BorgTranslatorImplanter + completetime: 2 + materials: + Steel: 500 + Glass: 500 + Plastic: 100 + Gold: 50 + Silver: 50 + +- type: latheRecipe + id: DwarfTranslatorImplanter + result: DwarfTranslatorImplanter + completetime: 2 + materials: + Steel: 500 + Glass: 500 + Plastic: 100 + Gold: 50 + Silver: 50 + - type: latheRecipe id: AnimalTranslator result: AnimalTranslator diff --git a/Resources/Prototypes/ADT/Research/translators.yml b/Resources/Prototypes/ADT/Research/translators.yml index b88b16ee385..3d411ca97f9 100644 --- a/Resources/Prototypes/ADT/Research/translators.yml +++ b/Resources/Prototypes/ADT/Research/translators.yml @@ -3,7 +3,7 @@ id: BasicTranslation name: research-technology-basic-translation icon: - sprite: _NF/Objects/Devices/translator.rsi + sprite: ADT/Objects/Devices/translator.rsi state: icon discipline: CivilianServices tier: 2 From f4b843749d9c4665f114268bde822acce54c6fbe Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Fri, 2 Aug 2024 09:31:58 +0400 Subject: [PATCH 03/15] what the fuck --- Resources/Prototypes/ADT/Recipes/Lathes/translators.yml | 4 ++-- Resources/Prototypes/ADT/Research/translators.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml b/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml index 55618550bbc..7ce2d0195b7 100644 --- a/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml +++ b/Resources/Prototypes/ADT/Recipes/Lathes/translators.yml @@ -69,8 +69,8 @@ Gold: 50 - type: latheRecipe - id: GalaticCommonTranslatorImplanter - result: GalaticCommonTranslatorImplanter + id: GalacticCommonTranslatorImplanter + result: GalacticCommonTranslatorImplanter completetime: 2 materials: Steel: 500 diff --git a/Resources/Prototypes/ADT/Research/translators.yml b/Resources/Prototypes/ADT/Research/translators.yml index 3d411ca97f9..795d7a79a66 100644 --- a/Resources/Prototypes/ADT/Research/translators.yml +++ b/Resources/Prototypes/ADT/Research/translators.yml @@ -33,7 +33,7 @@ id: AdvancedTranslation name: research-technology-advanced-translation icon: - sprite: _NF/Objects/Devices/translator.rsi + sprite: ADT/Objects/Devices/translator.rsi state: icon discipline: CivilianServices tier: 3 From 3ab787e79f026697ce3f435217f58fbb67deb609 Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Fri, 2 Aug 2024 09:39:28 +0400 Subject: [PATCH 04/15] =?UTF-8?q?=D0=BF=D0=BE=D1=87=D0=B5=D0=BC=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/Prototypes/ADT/Research/translators.yml | 2 +- Resources/Prototypes/Entities/Structures/Machines/lathe.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/ADT/Research/translators.yml b/Resources/Prototypes/ADT/Research/translators.yml index 795d7a79a66..35e3cf616ce 100644 --- a/Resources/Prototypes/ADT/Research/translators.yml +++ b/Resources/Prototypes/ADT/Research/translators.yml @@ -15,7 +15,7 @@ - DraconicTranslator - SolCommonTranslator - RootSpeakTranslator - - GalaticCommonTranslatorImplanter + - GalacticCommonTranslatorImplanter - MofficTranslator - DraskTranslator - UrsTranslator # Закомменчено до раундстарт урсов # И никто не раскомментил, молодцы diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index ed016046968..4a13a996112 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -342,7 +342,7 @@ - RootSpeakTranslator #- XenoTranslator - DraskTranslator - - GalaticCommonTranslatorImplanter + - GalacticCommonTranslatorImplanter - BubblishTranslatorImplanter - NekomimeticTranslatorImplanter - DraconicTranslatorImplanter From ac2f511baf342616a382fd4ead996284399a7528 Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Fri, 2 Aug 2024 17:30:19 +0400 Subject: [PATCH 05/15] =?UTF-8?q?=D0=9A=D0=B0=D0=BA=20=D0=B3=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D1=82=D1=81=D1=8F,=20Fix=20shit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Client/ADT/Language/LanguageSystem.cs | 4 +- .../ADT/Language/TranslatorImplantSystem.cs | 2 +- .../Language/UI/LanguageMenuWindow.xaml.cs | 4 +- Content.Client/Corvax/TTS/TTSSystem.cs | 4 +- Content.Client/Input/ContentContexts.cs | 2 +- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 2 +- .../Languages/LanguageMenuUIController.cs | 4 +- .../MenuBar/GameTopMenuBarUIController.cs | 8 +-- .../MenuBar/Widgets/GameTopMenuBar.xaml | 2 + Content.Server/ADT/Language/LanguageSystem.cs | 4 +- .../ADT/Language/TranslatorSystem.cs | 4 +- Content.Server/Chat/Systems/ChatSystem.cs | 70 +++++++++---------- Content.Server/Corvax/TTS/TTSSystem.cs | 25 ++++--- .../EntityEffects/Effects/MakeSentient.cs | 2 +- .../Mind/Commands/MakeSentientCommand.cs | 2 +- .../Radio/EntitySystems/HeadsetSystem.cs | 6 +- .../Radio/EntitySystems/RadioDeviceSystem.cs | 6 +- .../Radio/EntitySystems/RadioSystem.cs | 18 +++-- Content.Server/Radio/RadioEvent.cs | 4 +- .../Components/HandheldTranslatorComponent.cs | 2 +- .../Components/LanguageSpeakerComponent.cs | 2 +- .../ADT/Language/LanguagePrototype.cs | 2 +- .../Language/Systems/SharedLanguageSystem.cs | 2 +- .../Systems/SharedTranslatorImplantSystem.cs | 2 +- .../Systems/SharedTranslatorSystem.cs | 2 +- Content.Shared/Corvax/TTS/PlayTTSEvent.cs | 10 +-- .../Device/{Translators => }/handheld.yml | 1 + .../Translators => Misc}/implanters.yml | 1 + .../subdermal_implants.yml} | 1 + .../Entities/Structures/Machines/lathe.yml | 3 + 30 files changed, 111 insertions(+), 90 deletions(-) rename Resources/Prototypes/ADT/Entities/Objects/Device/{Translators => }/handheld.yml (99%) rename Resources/Prototypes/ADT/Entities/Objects/{Device/Translators => Misc}/implanters.yml (99%) rename Resources/Prototypes/ADT/Entities/Objects/{Device/Translators/implants.yml => Misc/subdermal_implants.yml} (99%) diff --git a/Content.Client/ADT/Language/LanguageSystem.cs b/Content.Client/ADT/Language/LanguageSystem.cs index 8312272ffc1..a56216ecfbb 100644 --- a/Content.Client/ADT/Language/LanguageSystem.cs +++ b/Content.Client/ADT/Language/LanguageSystem.cs @@ -1,4 +1,6 @@ -namespace Content.Shared.Language; +using Content.Shared.ADT.Language; + +namespace Content.Client.ADT.Language; public sealed partial class LanguageSystem : SharedLanguageSystem { diff --git a/Content.Client/ADT/Language/TranslatorImplantSystem.cs b/Content.Client/ADT/Language/TranslatorImplantSystem.cs index d34d770997e..83067d0669e 100644 --- a/Content.Client/ADT/Language/TranslatorImplantSystem.cs +++ b/Content.Client/ADT/Language/TranslatorImplantSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Implants; -namespace Content.Client.Implants; +namespace Content.Client.ADT.Implants; public sealed class TranslatorImplantSystem : SharedTranslatorImplantSystem { diff --git a/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs index 8492e15de40..e21bd9ca2e3 100644 --- a/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs +++ b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs @@ -1,4 +1,4 @@ -using Content.Shared.Language; +using Content.Shared.ADT.Language; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; @@ -12,9 +12,7 @@ namespace Content.Client.ADT.Language.UI; [GenerateTypedNameReferences] public sealed partial class LanguageMenuWindow : DefaultWindow { - [Dependency] private readonly IConsoleHost _consoleHost = default!; [Dependency] private readonly EntityManager _entManager = default!; - [Dependency] private readonly IEntityManager _iEntManager = default!; [Dependency] private readonly ISharedPlayerManager _playerManager = default!; diff --git a/Content.Client/Corvax/TTS/TTSSystem.cs b/Content.Client/Corvax/TTS/TTSSystem.cs index dc65f907b22..256e2cc5f76 100644 --- a/Content.Client/Corvax/TTS/TTSSystem.cs +++ b/Content.Client/Corvax/TTS/TTSSystem.cs @@ -8,7 +8,7 @@ using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.Utility; -using Content.Shared.Language; +using Content.Shared.ADT.Language; using Robust.Shared.Player; namespace Content.Client.Corvax.TTS; @@ -73,6 +73,7 @@ private void OnPlayTTS(PlayTTSEvent ev) var filePath = new ResPath($"{_fileIdx++}.ogg"); + // Languages TTS support start var player = _playerManager.LocalSession?.AttachedEntity; if (player != null) { @@ -83,6 +84,7 @@ private void OnPlayTTS(PlayTTSEvent ev) } else _contentRoot.AddOrUpdateFile(filePath, ev.Data); + // Languages TTS support end var audioResource = new AudioResource(); audioResource.Load(IoCManager.Instance!, Prefix / filePath); diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index d0dbace0b15..191bf7a2541 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -61,7 +61,7 @@ public static void SetupContexts(IInputContextContainer contexts) human.AddFunction(ContentKeyFunctions.AltUseItemInHand); human.AddFunction(ContentKeyFunctions.OpenCharacterMenu); human.AddFunction(ContentKeyFunctions.OpenEmotesMenu); - human.AddFunction(ContentKeyFunctions.OpenLanguagesMenu); + human.AddFunction(ContentKeyFunctions.OpenLanguagesMenu); // ADT Languages human.AddFunction(ContentKeyFunctions.ActivateItemInWorld); human.AddFunction(ContentKeyFunctions.ThrowItemInHand); human.AddFunction(ContentKeyFunctions.AltActivateItemInWorld); diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index af22be091a0..6f51b954917 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -216,7 +216,7 @@ void AddCheckBox(string checkBoxName, bool currentState, Action, IOnStateExited { diff --git a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs index 0b29310f71d..1c3b03483b9 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs +++ b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs @@ -9,7 +9,7 @@ using Content.Client.UserInterface.Systems.Guidebook; using Content.Client.UserInterface.Systems.MenuBar.Widgets; using Content.Client.UserInterface.Systems.Sandbox; -using Content.Client.UserInterface.Systems.Language; // Lang affected +using Content.Client.UserInterface.Systems.Language; // ADT Languages using Robust.Client.UserInterface.Controllers; namespace Content.Client.UserInterface.Systems.MenuBar; @@ -25,7 +25,7 @@ public sealed class GameTopMenuBarUIController : UIController [Dependency] private readonly SandboxUIController _sandbox = default!; [Dependency] private readonly GuidebookUIController _guidebook = default!; [Dependency] private readonly EmotesUIController _emotes = default!; - [Dependency] private readonly LanguageMenuUIController _language = default!; // Lang affected + [Dependency] private readonly LanguageMenuUIController _language = default!; // ADT Languages private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull(); @@ -49,7 +49,7 @@ public void UnloadButtons() _action.UnloadButton(); _sandbox.UnloadButton(); _emotes.UnloadButton(); - _language.UnloadButton(); // Lang affected + _language.UnloadButton(); // ADT Languages } public void LoadButtons() @@ -63,6 +63,6 @@ public void LoadButtons() _action.LoadButton(); _sandbox.LoadButton(); _emotes.LoadButton(); - _language.LoadButton(); // Lang affected + _language.LoadButton(); // ADT Languages } } diff --git a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml index 751a223bdf3..59640586174 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml +++ b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml @@ -53,6 +53,7 @@ HorizontalExpand="True" AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}" /> + + @@ -180,7 +180,7 @@ public void TrySendInGameICMessage( string? nameOverride = null, bool checkRadioPrefix = true, bool ignoreActionBlocker = false, - LanguagePrototype? language = null // Lang affected + LanguagePrototype? language = null // ADT Languages ) { if (HasComp(source)) @@ -224,7 +224,7 @@ public void TrySendInGameICMessage( message = message[1..]; } - // Lang start + // ADT Languages start bool shouldCapitalize = (desiredType != InGameICChatType.Emote); bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); @@ -234,7 +234,7 @@ public void TrySendInGameICMessage( string sanitizedMessage = SanitizeInGameICMessage(source, message, out var emoteStr, shouldCapitalize, shouldPunctuate, shouldCapitalizeTheWordI); - // Lang end + // ADT Languages end // Was there an emote in the message? If so, send it. if (player != null && emoteStr != message && emoteStr != null) @@ -260,13 +260,13 @@ public void TrySendInGameICMessage( switch (desiredType) { case InGameICChatType.Speak: - SendEntitySpeak(source, message, range, nameOverride, hideLog, ignoreActionBlocker, language); // Lang affected + SendEntitySpeak(source, message, range, nameOverride, hideLog, ignoreActionBlocker, language); // ADT Languages break; case InGameICChatType.Whisper: - SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker, language); // Lang affected + SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker, language); // ADT Languages break; case InGameICChatType.Emote: - SendEntityEmote(source, sanitizedMessage, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); // Accent fix + SendEntityEmote(source, sanitizedMessage, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker); // ADT Languages break; } } @@ -394,7 +394,7 @@ private void SendEntitySpeak( string? nameOverride, bool hideLog = false, bool ignoreActionBlocker = false, - LanguagePrototype? language = null // Lang affected + LanguagePrototype? language = null // ADT Languages ) { if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker) @@ -405,10 +405,10 @@ private void SendEntitySpeak( if (message.Length == 0) return; - // Lang start + // ADT Languages start if (language == null) language = _language.GetCurrentLanguage(source); - // Lang end + // ADT Languages end var speech = GetSpeechVerb(source, message); @@ -427,16 +427,14 @@ private void SendEntitySpeak( if (nameEv.SpeechVerb != null && _prototypeManager.TryIndex(nameEv.SpeechVerb, out var proto)) speech = proto; } - // Lang start - // Accent fix start + // ADT Languages start bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); // Capitalizing the word I only happens in English, so we check language here bool shouldCapitalizeTheWordI = (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en"); string coloredMessage = SanitizeInGameICMessage(source, FormattedMessage.EscapeText(message), out _, true, shouldPunctuate, shouldCapitalizeTheWordI); - // Accent fix end string coloredLanguageMessage = SanitizeInGameICMessage(source, _language.ObfuscateMessage(source, FormattedMessage.EscapeText(message), language), out _); @@ -448,7 +446,7 @@ private void SendEntitySpeak( coloredMessage = "[color=" + language.Color.Value.ToHex().ToString() + "]" + coloredMessage + "[/color]"; coloredLanguageMessage = "[color=" + language.Color.Value.ToHex().ToString() + "]" + coloredLanguageMessage + "[/color]"; } - // Lang end + // ADT Languages end name = FormattedMessage.EscapeText(name); var wrappedMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", @@ -456,17 +454,18 @@ private void SendEntitySpeak( ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), ("fontType", speech.FontId), ("fontSize", speech.FontSize), - ("message", coloredMessage)); // Lang affected + ("message", coloredMessage)); // ADT Language colored msg - // Lang start + // ADT Languages start var wrappedLanguageMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", ("entityName", name), ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), ("fontType", speech.FontId), ("fontSize", speech.FontSize), ("message", coloredLanguageMessage)); - // Lang end - SendInVoiceRange(ChatChannel.Local, message, wrappedMessage, wrappedLanguageMessage, source, range, language: language); // Lang affected + // ADT Languages end + + SendInVoiceRange(ChatChannel.Local, message, wrappedMessage, wrappedLanguageMessage, source, range, language: language); // ADT Languages var ev = new EntitySpokeEvent(source, message, language, null, null); RaiseLocalEvent(source, ev, true); @@ -502,7 +501,7 @@ private void SendEntityWhisper( string? nameOverride, bool hideLog = false, bool ignoreActionBlocker = false, - LanguagePrototype? language = null // Lang affected + LanguagePrototype? language = null // ADT Languages ) { if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker) @@ -514,13 +513,13 @@ private void SendEntityWhisper( var obfuscatedMessage = ObfuscateMessageReadability(message, 0.2f); - // Lang start + // ADT Languages start if (language == null) language = _language.GetCurrentLanguage(source); var languageMessage = SanitizeInGameICMessage(source, _language.ObfuscateMessage(source, message, language), out _); var obfuscatedLanguageMessage = ObfuscateMessageReadability(SanitizeInGameICMessage(source, _language.ObfuscateMessage(source, message, language), out _), 0.2f); - // Lang end + // ADT Languages end // get the entity's name by visual identity (if no override provided). string nameIdentity = FormattedMessage.EscapeText(nameOverride ?? Identity.Name(source, EntityManager)); @@ -536,9 +535,8 @@ private void SendEntityWhisper( RaiseLocalEvent(source, nameEv); name = nameEv.Name; } - // Lang start + // ADT Languages start - // Accent fix start bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation); // Capitalizing the word I only happens in English, so we check language here bool shouldCapitalizeTheWordI = (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") @@ -546,7 +544,6 @@ private void SendEntityWhisper( string coloredMessage = SanitizeInGameICMessage(source, FormattedMessage.EscapeText(message), out _, true, shouldPunctuate, shouldCapitalizeTheWordI); string coloredObfuscatedMessage = SanitizeInGameICMessage(source, FormattedMessage.EscapeText(obfuscatedMessage), out _, true, shouldPunctuate, shouldCapitalizeTheWordI); - // Accent fix end string coloredObfuscatedLanguageMessage = FormattedMessage.EscapeText(obfuscatedLanguageMessage); string coloredLanguageMessage = FormattedMessage.EscapeText(languageMessage); @@ -586,7 +583,8 @@ private void SendEntityWhisper( if (language == null) language = _language.GetCurrentLanguage(source); - // Lang end + // ADT Languages end + foreach (var (session, data) in GetRecipients(source, WhisperMuffledRange)) { EntityUid listener; @@ -598,7 +596,7 @@ private void SendEntityWhisper( if (MessageRangeCheck(session, data, range) != MessageRangeCheckResult.Full) continue; // Won't get logged to chat, and ghosts are too far away to see the pop-up, so we just won't send it to them. - // Lang start + // ADT Languages start if (!_language.CanUnderstand(source, language) && !_language.CheckTranslators(listener, source, language)) { if (data.Range <= WhisperClearRange) @@ -621,7 +619,7 @@ private void SendEntityWhisper( else _chatManager.ChatMessageToOne(ChatChannel.Whisper, obfuscatedMessage, wrappedUnknownMessage, source, false, session.Channel); } - // Lang end + // ADT Languages end } _replay.RecordServerMessage(new ChatMessage(ChatChannel.Whisper, message, wrappedMessage, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); @@ -673,7 +671,7 @@ private void SendEntityEmote( if (checkEmote) TryEmoteChatInput(source, action); - SendInVoiceRange(ChatChannel.Emotes, action, wrappedMessage, wrappedMessage, source, range, author, ignoreLanguage: true); // Lang affected + SendInVoiceRange(ChatChannel.Emotes, action, wrappedMessage, wrappedMessage, source, range, author, ignoreLanguage: true); // ADT Languages if (!hideLog) if (name != Name(source)) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}"); @@ -700,7 +698,7 @@ private void SendLOOC(EntityUid source, ICommonSession player, string message, b ("entityName", name), ("message", FormattedMessage.EscapeText(message))); - SendInVoiceRange(ChatChannel.LOOC, message, wrappedMessage, wrappedMessage, source, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, player.UserId, ignoreLanguage: true); // Lang affected + SendInVoiceRange(ChatChannel.LOOC, message, wrappedMessage, wrappedMessage, source, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, player.UserId, ignoreLanguage: true); // ADT Languages _adminLogger.Add(LogType.Chat, LogImpact.Low, $"LOOC from {player:Player}: {message}"); } @@ -781,9 +779,9 @@ 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 message, string wrappedMessage, string wrappedLanguageMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? language = null, bool ignoreLanguage = false) // Lang affected + private void SendInVoiceRange(ChatChannel channel, string message, string wrappedMessage, string wrappedLanguageMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? language = null, bool ignoreLanguage = false) // ADT Languages { - // Lang start + // ADT Languages start if (language == null) language = _language.GetCurrentLanguage(source); @@ -810,7 +808,7 @@ private void SendInVoiceRange(ChatChannel channel, string message, string wrappe else _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author); } - // Lang end + // ADT Languages end _replay.RecordServerMessage(new ChatMessage(channel, message, wrappedMessage, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); } diff --git a/Content.Server/Corvax/TTS/TTSSystem.cs b/Content.Server/Corvax/TTS/TTSSystem.cs index d18e4cbaea2..c8046212577 100644 --- a/Content.Server/Corvax/TTS/TTSSystem.cs +++ b/Content.Server/Corvax/TTS/TTSSystem.cs @@ -7,8 +7,8 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Content.Server.Language; -using Content.Shared.Language; +using Content.Server.ADT.Language; // ADT Languages +using Content.Shared.ADT.Language; // ADT Languages namespace Content.Server.Corvax.TTS; @@ -20,7 +20,7 @@ public sealed partial class TTSSystem : EntitySystem [Dependency] private readonly TTSManager _ttsManager = default!; [Dependency] private readonly SharedTransformSystem _xforms = default!; [Dependency] private readonly IRobustRandom _rng = default!; - [Dependency] private readonly LanguageSystem _language = default!; + [Dependency] private readonly LanguageSystem _language = default!; // ADT Languages private readonly List _sampleText = new() @@ -90,11 +90,11 @@ private async void OnEntitySpoke(EntityUid uid, TTSComponent component, EntitySp if (args.ObfuscatedMessage != null) { - HandleWhisper(uid, args.Message, args.ObfuscatedMessage, protoVoice.Speaker, args.Language); + HandleWhisper(uid, args.Message, args.ObfuscatedMessage, protoVoice.Speaker, args.Language); // ADT Languages return; } - HandleSay(uid, args.Message, protoVoice.Speaker, args.Language); + HandleSay(uid, args.Message, protoVoice.Speaker, args.Language); // ADT Languages } private async void HandleSay(EntityUid uid, string message, string speaker, LanguagePrototype language) @@ -102,9 +102,10 @@ private async void HandleSay(EntityUid uid, string message, string speaker, Lang var soundData = await GenerateTTS(message, speaker); if (soundData is null) return; + // ADT Languages start var languageSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, message, language), speaker); if (languageSoundData is null) return; - + // ADT Languages end RaiseNetworkEvent(new PlayTTSEvent(soundData, languageSoundData, language, GetNetEntity(uid)), Filter.Pvs(uid)); } @@ -114,17 +115,19 @@ private async void HandleWhisper(EntityUid uid, string message, string obfMessag var fullSoundData = await GenerateTTS(message, speaker, true); if (fullSoundData is null) return; - var fullLangSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, message, language), speaker, true); - if (fullLangSoundData is null) return; - var obfSoundData = await GenerateTTS(obfMessage, speaker, true); if (obfSoundData is null) return; + // ADT Languages start + var fullLangSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, message, language), speaker, true); + if (fullLangSoundData is null) return; + var obfLangSoundData = await GenerateTTS(_language.ObfuscateMessage(uid, obfMessage, language), speaker, true); if (obfLangSoundData is null) return; + // ADT Languages end - var fullTtsEvent = new PlayTTSEvent(fullSoundData, fullLangSoundData, language, GetNetEntity(uid), true); - var obfTtsEvent = new PlayTTSEvent(obfSoundData, obfLangSoundData, language, GetNetEntity(uid), true); + var fullTtsEvent = new PlayTTSEvent(fullSoundData, fullLangSoundData, language, GetNetEntity(uid), true); // ADT Languages + var obfTtsEvent = new PlayTTSEvent(obfSoundData, obfLangSoundData, language, GetNetEntity(uid), true); // ADT Languages // TODO: Check obstacles var xformQuery = GetEntityQuery(); diff --git a/Content.Server/EntityEffects/Effects/MakeSentient.cs b/Content.Server/EntityEffects/Effects/MakeSentient.cs index aad76a94ecf..72ef30578d9 100644 --- a/Content.Server/EntityEffects/Effects/MakeSentient.cs +++ b/Content.Server/EntityEffects/Effects/MakeSentient.cs @@ -3,7 +3,7 @@ using Content.Shared.EntityEffects; using Content.Shared.Mind.Components; using Robust.Shared.Prototypes; -using Content.Shared.Language; +using Content.Shared.ADT.Language; namespace Content.Server.EntityEffects.Effects; diff --git a/Content.Server/Mind/Commands/MakeSentientCommand.cs b/Content.Server/Mind/Commands/MakeSentientCommand.cs index 80a5c7b71eb..35244850406 100644 --- a/Content.Server/Mind/Commands/MakeSentientCommand.cs +++ b/Content.Server/Mind/Commands/MakeSentientCommand.cs @@ -6,7 +6,7 @@ using Content.Shared.Movement.Components; using Content.Shared.Speech; using Robust.Shared.Console; -using Content.Shared.Language; +using Content.Shared.ADT.Language; namespace Content.Server.Mind.Commands { diff --git a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs index 34a8a4c2a58..f62ae1f5b3d 100644 --- a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs +++ b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs @@ -7,7 +7,7 @@ using Content.Shared.Radio.EntitySystems; using Robust.Shared.Network; using Robust.Shared.Player; -using Content.Server.Language; +using Content.Server.ADT.Language; // ADT Languages namespace Content.Server.Radio.EntitySystems; @@ -15,7 +15,7 @@ public sealed class HeadsetSystem : SharedHeadsetSystem { [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly RadioSystem _radio = default!; - [Dependency] private readonly LanguageSystem _language = default!; + [Dependency] private readonly LanguageSystem _language = default!; // ADT Languages public override void Initialize() { @@ -103,10 +103,12 @@ private void OnHeadsetReceive(EntityUid uid, HeadsetComponent component, ref Rad { if (TryComp(Transform(uid).ParentUid, out ActorComponent? actor)) { + // ADT Languages start if (_language.CanUnderstand(Transform(uid).ParentUid, args.Language)) _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel); else _netMan.ServerSendMessage(args.UnknownLanguageChatMsg, actor.PlayerSession.Channel); + // ADT Languages end } } diff --git a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs index b92142aa9a2..05db1e21e36 100644 --- a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs @@ -1,7 +1,7 @@ using System.Linq; using Content.Server.Chat.Systems; using Content.Server.Interaction; -using Content.Server.Language; +using Content.Server.ADT.Language; // ADT Languages using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; @@ -27,7 +27,7 @@ public sealed class RadioDeviceSystem : EntitySystem [Dependency] private readonly RadioSystem _radio = default!; [Dependency] private readonly InteractionSystem _interaction = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly LanguageSystem _language = default!; + [Dependency] private readonly LanguageSystem _language = default!; // ADT Languages // Used to prevent a shitter from using a bunch of radios to spam chat. private HashSet<(string, EntityUid)> _recentlySent = new(); @@ -217,7 +217,7 @@ private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, ref ("originalName", nameEv.Name)); // log to chat so people can identity the speaker/source, but avoid clogging ghost chat if there are many radios - _chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false, language: args.Language); + _chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false, language: args.Language); // ADT Languages } private void OnIntercomEncryptionChannelsChanged(Entity ent, ref EncryptionChannelsChangedEvent args) diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index f5566bcc190..68bcc859489 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -15,8 +15,8 @@ using Robust.Shared.Random; using Robust.Shared.Replays; using Robust.Shared.Utility; -using Content.Server.Language; -using Content.Shared.Language; +using Content.Server.ADT.Language; // ADT Languages +using Content.Shared.ADT.Language; // ADT Languages namespace Content.Server.Radio.EntitySystems; @@ -31,7 +31,7 @@ public sealed class RadioSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ChatSystem _chat = default!; - [Dependency] private readonly LanguageSystem _language = default!; + [Dependency] private readonly LanguageSystem _language = default!; // ADT Languages // set used to prevent radio feedback loops. private readonly HashSet _messages = new(); @@ -60,10 +60,12 @@ private void OnIntrinsicReceive(EntityUid uid, IntrinsicRadioReceiverComponent c { if (TryComp(uid, out ActorComponent? actor)) { + // ADT Languages start if (_language.CanUnderstand(uid, args.Language)) _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel); else _netMan.ServerSendMessage(args.UnknownLanguageChatMsg, actor.PlayerSession.Channel); + // ADT Languages end } } @@ -109,6 +111,7 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann ? FormattedMessage.EscapeText(message) : message; + // ADT Languages start var languageEncodedContent = _language.ObfuscateMessage(messageSource, content, language); if (language.Color != null) @@ -116,6 +119,7 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann content = "[color=" + language.Color.Value.ToHex().ToString() + "]" + FormattedMessage.EscapeText(content) + "[/color]"; languageEncodedContent = "[color=" + language.Color.Value.ToHex().ToString() + "]" + FormattedMessage.EscapeText(languageEncodedContent) + "[/color]"; } + // ADT Languages end var wrappedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", ("color", channel.Color), @@ -126,6 +130,7 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann ("name", name), ("message", content)); + // ADT Languages start var wrappedEncodedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", ("color", channel.Color), ("fontType", speech.FontId), @@ -134,6 +139,7 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann ("channel", $"\\[{channel.LocalizedName}\\]"), ("name", name), ("message", languageEncodedContent)); + // ADT Languages end // most radios are relayed to chat, so lets parse the chat message beforehand var chat = new ChatMessage( @@ -143,17 +149,19 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann NetEntity.Invalid, null); + // ADT Languages start var encodedChat = new ChatMessage( ChatChannel.Radio, message, wrappedEncodedMessage, NetEntity.Invalid, null); + // ADT Languages end var chatMsg = new MsgChatMessage { Message = chat }; - var encodedChatMsg = new MsgChatMessage { Message = chat }; + var encodedChatMsg = new MsgChatMessage { Message = encodedChat }; // ADT Languages - var ev = new RadioReceiveEvent(message, messageSource, channel, radioSource, chatMsg, encodedChatMsg, language); + var ev = new RadioReceiveEvent(message, messageSource, channel, radioSource, chatMsg, encodedChatMsg, language); // ADT Languages var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource); RaiseLocalEvent(ref sendAttemptEv); diff --git a/Content.Server/Radio/RadioEvent.cs b/Content.Server/Radio/RadioEvent.cs index fbc862df13b..4cdc4213e2f 100644 --- a/Content.Server/Radio/RadioEvent.cs +++ b/Content.Server/Radio/RadioEvent.cs @@ -1,11 +1,11 @@ using Content.Shared.Chat; using Content.Shared.Radio; -using Content.Shared.Language; // Lang affected +using Content.Shared.ADT.Language; // ADT Languages namespace Content.Server.Radio; [ByRefEvent] -public readonly record struct RadioReceiveEvent(string Message, EntityUid MessageSource, RadioChannelPrototype Channel, EntityUid RadioSource, MsgChatMessage ChatMsg, MsgChatMessage UnknownLanguageChatMsg, LanguagePrototype Language); // Lang affected +public readonly record struct RadioReceiveEvent(string Message, EntityUid MessageSource, RadioChannelPrototype Channel, EntityUid RadioSource, MsgChatMessage ChatMsg, MsgChatMessage UnknownLanguageChatMsg, LanguagePrototype Language); // ADT Languages /// /// Use this event to cancel sending message per receiver diff --git a/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs b/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs index 86aafe3e68c..93aabaf7e13 100644 --- a/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs +++ b/Content.Shared/ADT/Language/Components/HandheldTranslatorComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -namespace Content.Shared.Language; +namespace Content.Shared.ADT.Language; [RegisterComponent, NetworkedComponent] public sealed partial class HandheldTranslatorComponent : Component diff --git a/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs b/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs index b524a1abe3f..66da42ef2fd 100644 --- a/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs +++ b/Content.Shared/ADT/Language/Components/LanguageSpeakerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.GameStates; -namespace Content.Shared.Language; +namespace Content.Shared.ADT.Language; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class LanguageSpeakerComponent : Component diff --git a/Content.Shared/ADT/Language/LanguagePrototype.cs b/Content.Shared/ADT/Language/LanguagePrototype.cs index 598b14f14cc..1361ae28940 100644 --- a/Content.Shared/ADT/Language/LanguagePrototype.cs +++ b/Content.Shared/ADT/Language/LanguagePrototype.cs @@ -2,7 +2,7 @@ using Robust.Shared.GameStates; using Robust.Shared.Serialization; -namespace Content.Shared.Language; +namespace Content.Shared.ADT.Language; [Prototype("language")] public sealed class LanguagePrototype : IPrototype diff --git a/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs b/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs index 4f940f232e2..98deab329fb 100644 --- a/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs @@ -6,7 +6,7 @@ using Content.Shared.Ghost; using Robust.Shared.Network; -namespace Content.Shared.Language; +namespace Content.Shared.ADT.Language; public abstract class SharedLanguageSystem : EntitySystem { diff --git a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs index 0fad22f50f0..abb3cf95cd9 100644 --- a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs @@ -8,7 +8,7 @@ using JetBrains.Annotations; using Robust.Shared.Containers; using Robust.Shared.Network; -using Content.Shared.Language; +using Content.Shared.ADT.Language; namespace Content.Shared.Implants; diff --git a/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs b/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs index 1cb350a658c..8e5353d3b4c 100644 --- a/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedTranslatorSystem.cs @@ -1,7 +1,7 @@ using Content.Shared.Examine; using Content.Shared.Toggleable; -namespace Content.Shared.Language; +namespace Content.Shared.ADT.Language; public abstract class SharedTranslatorSystem : EntitySystem { diff --git a/Content.Shared/Corvax/TTS/PlayTTSEvent.cs b/Content.Shared/Corvax/TTS/PlayTTSEvent.cs index 24aab224d1c..144f32b71a4 100644 --- a/Content.Shared/Corvax/TTS/PlayTTSEvent.cs +++ b/Content.Shared/Corvax/TTS/PlayTTSEvent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Language; +using Content.Shared.ADT.Language; // ADT Languages using Robust.Shared.Serialization; namespace Content.Shared.Corvax.TTS; @@ -11,13 +11,13 @@ public sealed class PlayTTSEvent : EntityEventArgs public byte[] LanguageData { get; } public NetEntity? SourceUid { get; } public bool IsWhisper { get; } - public string LanguageProtoId { get; } - public PlayTTSEvent(byte[] data, byte[] languageData, LanguagePrototype language, NetEntity? sourceUid = null, bool isWhisper = false) + public string LanguageProtoId { get; } // ADT Languages + public PlayTTSEvent(byte[] data, byte[] languageData, LanguagePrototype language, NetEntity? sourceUid = null, bool isWhisper = false) // ADT Languages { Data = data; SourceUid = sourceUid; IsWhisper = isWhisper; - LanguageProtoId = language.ID; - LanguageData = languageData; + LanguageProtoId = language.ID; // ADT Languages + LanguageData = languageData; // ADT Languages } } diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml similarity index 99% rename from Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml rename to Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml index 12ac3ee751b..7dd3cd21720 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/handheld.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml @@ -1,3 +1,4 @@ +# Translators - type: entity id: TranslatorUnpowered parent: [ BaseItem ] diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml b/Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml similarity index 99% rename from Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml rename to Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml index 0500bf469c7..8abe4059289 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implanters.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Misc/implanters.yml @@ -1,3 +1,4 @@ +# Translators - type: entity id: GalacticCommonTranslatorImplanter name: Galactic Common Translator implanter diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml b/Resources/Prototypes/ADT/Entities/Objects/Misc/subdermal_implants.yml similarity index 99% rename from Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml rename to Resources/Prototypes/ADT/Entities/Objects/Misc/subdermal_implants.yml index 702dce1a09b..2bd1b012801 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/Translators/implants.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Misc/subdermal_implants.yml @@ -1,3 +1,4 @@ +# Translators - type: entity id: BaseTranslatorImplant abstract: true diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 4a13a996112..19619610109 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -360,6 +360,9 @@ - ArkaneTranslatorImplanter - ShadowkinTranslatorImplanter - CintaTajTranslatorImplanter + - IPCTranslatorImplanter + - BorgTranslatorImplanter + - DwarfTranslatorImplanter - UrsTranslator - ArkaneTranslator - ShadowkinTranslator From bda22235092e86646c44eec692dc18382174d5f4 Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Fri, 2 Aug 2024 17:33:14 +0400 Subject: [PATCH 06/15] =?UTF-8?q?=D0=B5=D1=89=D1=91=20=D0=BC=D0=B8=D0=BD?= =?UTF-8?q?=D0=B8=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Client/Corvax/TTS/TTSSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Client/Corvax/TTS/TTSSystem.cs b/Content.Client/Corvax/TTS/TTSSystem.cs index 256e2cc5f76..fc843fc873a 100644 --- a/Content.Client/Corvax/TTS/TTSSystem.cs +++ b/Content.Client/Corvax/TTS/TTSSystem.cs @@ -8,7 +8,7 @@ using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.Utility; -using Content.Shared.ADT.Language; +using Content.Shared.ADT.Language; // ADT Languages using Robust.Shared.Player; namespace Content.Client.Corvax.TTS; @@ -23,7 +23,7 @@ public sealed class TTSSystem : EntitySystem [Dependency] private readonly IResourceManager _res = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly ISharedPlayerManager _playerManager = default!; - [Dependency] private readonly SharedLanguageSystem _language = default!; + [Dependency] private readonly SharedLanguageSystem _language = default!; // ADT Languages private ISawmill _sawmill = default!; private readonly MemoryContentRoot _contentRoot = new(); From 3f751f3302b2747781ca04e82d19ae6999e23c9c Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Sat, 3 Aug 2024 21:34:21 +0400 Subject: [PATCH 07/15] =?UTF-8?q?=D0=A4=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=88=D1=82=D1=80=D0=B8=D1=85=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Language/UI/LanguageMenuWindow.xaml.cs | 47 +++++++++++++++++-- Content.Server/ADT/Language/LanguageSystem.cs | 8 ++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs index e21bd9ca2e3..e9d8d39185d 100644 --- a/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs +++ b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs @@ -19,6 +19,7 @@ public sealed partial class LanguageMenuWindow : DefaultWindow private readonly SharedLanguageSystem _language; private readonly List _entries = new(); + private readonly List [RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState] public sealed partial class HandheldTranslatorComponent : Component { [ViewVariables(VVAccess.ReadWrite)] - [DataField("toUnderstand", required: true)] + [DataField("toUnderstand", required: true), AutoNetworkedField] public List ToUnderstand; [ViewVariables(VVAccess.ReadWrite)] - [DataField("toSpeak", required: true)] + [DataField("toSpeak", required: true), AutoNetworkedField] public List ToSpeak; [ViewVariables(VVAccess.ReadWrite)] - [DataField("requires", required: true)] + [DataField("required", required: true), AutoNetworkedField] public List Required; [ViewVariables(VVAccess.ReadWrite)] [DataField("toggle")] public bool ToggleOnInteract = true; - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] [DataField] public bool Enabled = false; diff --git a/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs b/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs index fce20ada220..d0f3cffa67e 100644 --- a/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedLanguageSystem.cs @@ -114,91 +114,6 @@ public bool CanUnderstand(EntityUid uid, string protoId, LanguageSpeakerComponen return false; } - // Unholy shit - public bool CheckTranslators(EntityUid uid, EntityUid source, LanguagePrototype proto) - { - if (!TryComp(uid, out var uidManager)) - return false; - if (!TryComp(uid, out var comp)) - return false; - bool canTranslate = false; - bool canUnderstandTranslator = false; - - foreach (var container in uidManager.Containers.Values) - { - foreach (var entity in container.ContainedEntities) - { - if (TryComp(entity, out var translator) && translator.Enabled) - { - foreach (var item in translator.ToUnderstand) - { - if (item == proto.ID) - canTranslate = true; - } - if (!TryComp(uid, out var sourceLang)) - { - canUnderstandTranslator = false; - continue; - } - - foreach (var lang in translator.ToSpeak) - { - foreach (var understoodLangs in sourceLang.UnderstoodLanguages) - { - if (lang == understoodLangs) - canUnderstandTranslator = true; - } - } - - } - } - } - - if (canTranslate && canUnderstandTranslator) - return true; - - canTranslate = false; - canUnderstandTranslator = false; - - if (!TryComp(source, out var sourceManager)) - return false; - - foreach (var container in sourceManager.Containers.Values) - { - foreach (var entity in container.ContainedEntities) - { - if (TryComp(entity, out var translator) && translator.Enabled) - { - foreach (var item in translator.ToSpeak) - { - if (item == proto.ID) - canTranslate = true; - } - if (!TryComp(source, out var sourceLang)) - { - canUnderstandTranslator = false; - continue; - } - - foreach (var lang in translator.ToUnderstand) - { - foreach (var understoodLangs in sourceLang.SpokenLanguages) - { - if (lang == understoodLangs) - canUnderstandTranslator = true; - } - } - - } - } - } - - if (canTranslate && canUnderstandTranslator) - return true; - - return false; - } - public LanguagePrototype GetCurrentLanguage(EntityUid uid) { var universalProto = _proto.Index("Universal"); @@ -269,15 +184,14 @@ public bool GetLanguages( { if (understood.Contains(lang)) { - understood.AddRange(translator.ToUnderstand); - spoken.AddRange(translator.ToSpeak); + translatorUnderstood.AddRange(translator.ToUnderstand); + translatorSpoken.AddRange(translator.ToSpeak); break; } } } } - if (understood.Count <= 0 || spoken.Count <= 0 || current == String.Empty) return false; diff --git a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs index 3a19eb60b45..7f31a8e5dfa 100644 --- a/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs +++ b/Content.Shared/ADT/Language/Systems/SharedTranslatorImplantSystem.cs @@ -10,8 +10,6 @@ namespace Content.Shared.Implants; public abstract class SharedTranslatorImplantSystem : EntitySystem { [Dependency] private readonly INetManager _net = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedLanguageSystem _language = default!; public override void Initialize() @@ -55,10 +53,10 @@ private void OnInsert(EntityUid uid, TranslatorImplantComponent component, EntGo Dirty(component.ImplantedEntity.Value, languageSpeaker); - if (!_language.GetLanguages(component.ImplantedEntity.Value, out var understood, out _, out var current)) + if (!_language.GetLanguages(component.ImplantedEntity.Value, out var understood, out _, out var translatorUnderstood, out _, out var current)) return; - var menuEv = new LanguageMenuStateMessage(GetNetEntity(component.ImplantedEntity.Value), current, understood); + var menuEv = new LanguageMenuStateMessage(GetNetEntity(component.ImplantedEntity.Value), current, understood, translatorUnderstood); RaiseNetworkEvent(menuEv); var ev = new ImplantImplantedEvent(uid, component.ImplantedEntity.Value); @@ -102,10 +100,10 @@ private void OnRemove(EntityUid uid, TranslatorImplantComponent component, EntGo Dirty(component.ImplantedEntity.Value, languageSpeaker); - if (!_language.GetLanguages(component.ImplantedEntity.Value, out var understood, out _, out var current)) + if (!_language.GetLanguages(component.ImplantedEntity.Value, out var understood, out _, out var translatorUnderstood, out _, out var current)) return; - var menuEv = new LanguageMenuStateMessage(GetNetEntity(component.ImplantedEntity.Value), current, understood); + var menuEv = new LanguageMenuStateMessage(GetNetEntity(component.ImplantedEntity.Value), current, understood, translatorUnderstood); RaiseNetworkEvent(menuEv); component.ImplantedEntity = null; diff --git a/Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml b/Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml index 51b142a1408..657da893ded 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Device/handheld.yml @@ -27,6 +27,8 @@ - GalacticCommon toUnderstand: - GalacticCommon + required: + - GalacticCommon enabled: false - type: ItemToggle From 6e9e4aaf841f7fd91ac6685466179882233cf0b9 Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Tue, 6 Aug 2024 21:19:31 +0400 Subject: [PATCH 14/15] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D1=87=D0=B8=D0=BA=D0=B8=20=D0=B7=D0=B0=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=BB=D0=B8=20=D0=BA=D0=B0=D0=BA=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=B4=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Language/UI/LanguageMenuWindow.xaml.cs | 39 ++++++++----------- .../Languages/LanguageMenuUIController.cs | 1 - .../ADT/Language/TranslatorSystem.cs | 21 ++++++++-- .../Components/HandheldTranslatorComponent.cs | 1 + .../Language/Systems/SharedLanguageSystem.cs | 18 ++++++++- .../ADT/prototypes/Actions/language-menu.ftl | 4 +- .../Entities/Objects/Device/translators.ftl | 4 +- 7 files changed, 56 insertions(+), 32 deletions(-) diff --git a/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs index 087a8a93a3d..095e5148ff9 100644 --- a/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs +++ b/Content.Client/ADT/Language/UI/LanguageMenuWindow.xaml.cs @@ -41,20 +41,19 @@ public void UpdateState(LanguageMenuStateMessage state) { CurrentLanguageLabel.Text = Loc.GetString("language-menu-current-language", ("language", _language.GetLanguage(state.CurrentLanguage).LocalizedName)); - //OptionsList.RemoveAllChildren(); List options = new(); List