mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 13:37:47 +03:00
# Description UniversalLanguageSpeakerComponent has NUMEROUS issues, which previously were easy to ignore since it was a language only obtainable by Admins. But now that it's both a Psionic Power(And a trait that adds said power), the issues with it have been highlighted. Here's just a FEW 1. UniversalLanguageSpeaker overwrites all known languages, preventing you from speaking anything else 2. It overwrites the ability to use sign language. 3. It also overwrites the Mute trait. To fix that, I've made it follow *MOSTLY* the logic all the other languages use, so that it's less of a special snowflake case. Now if you have access to it, it will appear in your language list alongside other languages, rather than fully replacing the entire list. That way you can intentionally choose not to speak in a language understood by all. Fuck it, I also added the ability for the TraitSystem to just call LanguageSystem and directly add arbitrarily any desired language, rather than needing a component to do so. # Changelog 🆑 - fix: UniversalLanguageSpeaker(And Xenoglossy by extension) will now appear in your language menu alongside other known languages, rather than replace all known languages. You can effectively now choose whether or not to speak it, or to use a normal language. - add: Traits can now add Languages directly. - add: Traits can now remove Languages directly. --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Co-authored-by: FoxxoTrystan <45297731+FoxxoTrystan@users.noreply.github.com> Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com>
165 lines
7.0 KiB
C#
165 lines
7.0 KiB
C#
using System.Linq;
|
|
using Content.Server.Popups;
|
|
using Content.Server.PowerCell;
|
|
using Content.Shared.Interaction;
|
|
using Content.Shared.Interaction.Events;
|
|
using Content.Shared.Language;
|
|
using Content.Shared.Language.Components;
|
|
using Content.Shared.Language.Systems;
|
|
using Content.Shared.PowerCell;
|
|
using Content.Shared.Language.Components.Translators;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Server.Language;
|
|
|
|
public sealed class TranslatorSystem : SharedTranslatorSystem
|
|
{
|
|
[Dependency] private readonly SharedContainerSystem _containers = default!;
|
|
[Dependency] private readonly PopupSystem _popup = default!;
|
|
[Dependency] private readonly LanguageSystem _language = default!;
|
|
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<IntrinsicTranslatorComponent, DetermineEntityLanguagesEvent>(OnDetermineLanguages);
|
|
SubscribeLocalEvent<HoldsTranslatorComponent, DetermineEntityLanguagesEvent>(OnProxyDetermineLanguages);
|
|
|
|
SubscribeLocalEvent<HandheldTranslatorComponent, EntGotInsertedIntoContainerMessage>(OnTranslatorInserted);
|
|
SubscribeLocalEvent<HandheldTranslatorComponent, EntParentChangedMessage>(OnTranslatorParentChanged);
|
|
SubscribeLocalEvent<HandheldTranslatorComponent, ActivateInWorldEvent>(OnTranslatorToggle);
|
|
SubscribeLocalEvent<HandheldTranslatorComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);
|
|
}
|
|
|
|
private void OnDetermineLanguages(EntityUid uid, IntrinsicTranslatorComponent component, DetermineEntityLanguagesEvent ev)
|
|
{
|
|
if (!component.Enabled
|
|
|| component.LifeStage >= ComponentLifeStage.Removing
|
|
|| !TryComp<LanguageKnowledgeComponent>(uid, out var knowledge)
|
|
|| !_powerCell.HasActivatableCharge(uid))
|
|
return;
|
|
|
|
CopyLanguages(component, ev, knowledge);
|
|
}
|
|
|
|
private void OnProxyDetermineLanguages(EntityUid uid, HoldsTranslatorComponent component, DetermineEntityLanguagesEvent ev)
|
|
{
|
|
if (!TryComp<LanguageKnowledgeComponent>(uid, out var knowledge))
|
|
return;
|
|
|
|
foreach (var (translator, translatorComp) in component.Translators.ToArray())
|
|
{
|
|
if (!translatorComp.Enabled || !_powerCell.HasActivatableCharge(uid))
|
|
continue;
|
|
|
|
if (!_containers.TryGetContainingContainer(translator, out var container) || container.Owner != uid)
|
|
{
|
|
component.Translators.RemoveWhere(it => it.Owner == translator);
|
|
continue;
|
|
}
|
|
|
|
CopyLanguages(translatorComp, ev, knowledge);
|
|
}
|
|
}
|
|
|
|
private void OnTranslatorInserted(EntityUid translator, HandheldTranslatorComponent component, EntGotInsertedIntoContainerMessage args)
|
|
{
|
|
if (args.Container.Owner is not {Valid: true} holder || !HasComp<LanguageSpeakerComponent>(holder))
|
|
return;
|
|
|
|
var intrinsic = EnsureComp<HoldsTranslatorComponent>(holder);
|
|
intrinsic.Translators.Add((translator, component));
|
|
|
|
_language.UpdateEntityLanguages(holder);
|
|
}
|
|
|
|
private void OnTranslatorParentChanged(EntityUid translator, HandheldTranslatorComponent component, EntParentChangedMessage args)
|
|
{
|
|
if (!HasComp<HoldsTranslatorComponent>(args.OldParent))
|
|
return;
|
|
|
|
// Update the translator on the next tick - this is necessary because there's a good chance the removal from a container
|
|
// Was caused by the player moving the translator within their inventory rather than removing it.
|
|
// If that is not the case, then OnProxyDetermineLanguages will remove this translator from HoldsTranslatorComponent.Translators.
|
|
Timer.Spawn(0, () =>
|
|
{
|
|
if (Exists(args.OldParent) && HasComp<LanguageSpeakerComponent>(args.OldParent))
|
|
_language.UpdateEntityLanguages(args.OldParent.Value);
|
|
});
|
|
}
|
|
|
|
private void OnTranslatorToggle(EntityUid translator, HandheldTranslatorComponent translatorComp, ActivateInWorldEvent args)
|
|
{
|
|
if (!translatorComp.ToggleOnInteract)
|
|
return;
|
|
|
|
// This will show a popup if false
|
|
var hasPower = _powerCell.HasDrawCharge(translator);
|
|
var isEnabled = !translatorComp.Enabled && hasPower;
|
|
|
|
translatorComp.Enabled = isEnabled;
|
|
_powerCell.SetPowerCellDrawEnabled(translator, isEnabled);
|
|
|
|
if (_containers.TryGetContainingContainer(translator, out var holderCont)
|
|
&& holderCont.Owner is var holder
|
|
&& TryComp<LanguageSpeakerComponent>(holder, out var languageComp))
|
|
{
|
|
// The first new spoken language added by this translator, or null
|
|
var firstNewLanguage = translatorComp.SpokenLanguages.FirstOrDefault(it => !languageComp.SpokenLanguages.Contains(it));
|
|
_language.UpdateEntityLanguages(holder);
|
|
|
|
// Update the current language of the entity if necessary
|
|
if (isEnabled && translatorComp.SetLanguageOnInteract && firstNewLanguage is {})
|
|
_language.SetLanguage(holder, firstNewLanguage, languageComp);
|
|
}
|
|
|
|
OnAppearanceChange(translator, translatorComp);
|
|
|
|
if (hasPower)
|
|
{
|
|
var loc = isEnabled ? "translator-component-turnon" : "translator-component-shutoff";
|
|
var message = Loc.GetString(loc, ("translator", translator));
|
|
_popup.PopupEntity(message, translator, args.User);
|
|
}
|
|
}
|
|
|
|
private void OnPowerCellSlotEmpty(EntityUid translator, HandheldTranslatorComponent component, PowerCellSlotEmptyEvent args)
|
|
{
|
|
component.Enabled = false;
|
|
_powerCell.SetPowerCellDrawEnabled(translator, false);
|
|
OnAppearanceChange(translator, component);
|
|
|
|
if (_containers.TryGetContainingContainer(translator, out var holderCont) && HasComp<LanguageSpeakerComponent>(holderCont.Owner))
|
|
_language.UpdateEntityLanguages(holderCont.Owner);
|
|
}
|
|
|
|
private void CopyLanguages(BaseTranslatorComponent from, DetermineEntityLanguagesEvent to, LanguageKnowledgeComponent knowledge)
|
|
{
|
|
var addSpoken = CheckLanguagesMatch(from.RequiredLanguages, knowledge.SpokenLanguages, from.RequiresAllLanguages);
|
|
var addUnderstood = CheckLanguagesMatch(from.RequiredLanguages, knowledge.UnderstoodLanguages, from.RequiresAllLanguages);
|
|
|
|
if (addSpoken)
|
|
foreach (var language in from.SpokenLanguages)
|
|
to.SpokenLanguages.Add(language);
|
|
|
|
if (addUnderstood)
|
|
foreach (var language in from.UnderstoodLanguages)
|
|
to.UnderstoodLanguages.Add(language);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether any OR all required languages are provided. Used for utility purposes.
|
|
/// </summary>
|
|
public static bool CheckLanguagesMatch(ICollection<string> required, ICollection<string> provided, bool requireAll)
|
|
{
|
|
if (required.Count == 0)
|
|
return true;
|
|
|
|
return requireAll
|
|
? required.All(provided.Contains)
|
|
: required.Any(provided.Contains);
|
|
}
|
|
}
|