mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-28 11:07:50 +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>
106 lines
4.4 KiB
C#
106 lines
4.4 KiB
C#
using System.Linq;
|
|
using Content.Server.Hands.Systems;
|
|
using Content.Server.Language;
|
|
using Content.Server.Storage.EntitySystems;
|
|
using Content.Shared.Clothing.Components;
|
|
using Content.Shared.Inventory;
|
|
using Content.Shared.Language;
|
|
using Content.Shared.Language.Components;
|
|
using Content.Shared.Language.Components.Translators;
|
|
using Content.Shared.Storage;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Server.Traits.Assorted;
|
|
|
|
|
|
public sealed partial class ForeignerTraitSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly EntityManager _entMan = default!;
|
|
[Dependency] private readonly HandsSystem _hands = default!;
|
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
|
[Dependency] private readonly LanguageSystem _languages = default!;
|
|
[Dependency] private readonly StorageSystem _storage = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
SubscribeLocalEvent<ForeignerTraitComponent, ComponentInit>(OnSpawn); // TraitSystem adds it after PlayerSpawnCompleteEvent so it's fine
|
|
}
|
|
|
|
private void OnSpawn(Entity<ForeignerTraitComponent> entity, ref ComponentInit args)
|
|
{
|
|
if (entity.Comp.CantUnderstand && !entity.Comp.CantSpeak)
|
|
Log.Warning($"Allowing entity {entity.Owner} to speak a language but not understand it leads to undefined behavior.");
|
|
|
|
if (!TryComp<LanguageKnowledgeComponent>(entity, out var knowledge))
|
|
{
|
|
Log.Warning($"Entity {entity.Owner} does not have a LanguageKnowledge but has a ForeignerTrait!");
|
|
return;
|
|
}
|
|
|
|
var alternateLanguage = knowledge.SpokenLanguages.Find(it => it != entity.Comp.BaseLanguage);
|
|
if (alternateLanguage == null)
|
|
{
|
|
Log.Warning($"Entity {entity.Owner} does not have an alternative language to choose from (must have at least one non-GC for ForeignerTrait)!");
|
|
return;
|
|
}
|
|
|
|
if (TryGiveTranslator(entity.Owner, entity.Comp.BaseTranslator, entity.Comp.BaseLanguage, alternateLanguage, out var translator))
|
|
{
|
|
_languages.RemoveLanguage(entity, entity.Comp.BaseLanguage, entity.Comp.CantSpeak, entity.Comp.CantUnderstand);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to create and give the entity a translator to translator that translates speech between the two specified languages.
|
|
/// </summary>
|
|
public bool TryGiveTranslator(
|
|
EntityUid uid,
|
|
string baseTranslatorPrototype,
|
|
ProtoId<LanguagePrototype> translatorLanguage,
|
|
ProtoId<LanguagePrototype> entityLanguage,
|
|
out EntityUid result)
|
|
{
|
|
result = EntityUid.Invalid;
|
|
if (translatorLanguage == entityLanguage)
|
|
return false;
|
|
|
|
var translator = _entMan.SpawnNextToOrDrop(baseTranslatorPrototype, uid);
|
|
result = translator;
|
|
|
|
if (!TryComp<HandheldTranslatorComponent>(translator, out var handheld))
|
|
{
|
|
handheld = AddComp<HandheldTranslatorComponent>(translator);
|
|
handheld.ToggleOnInteract = true;
|
|
handheld.SetLanguageOnInteract = true;
|
|
}
|
|
|
|
// Allows to speak the specified language and requires entities language.
|
|
handheld.SpokenLanguages = [translatorLanguage];
|
|
handheld.UnderstoodLanguages = [translatorLanguage];
|
|
handheld.RequiredLanguages = [entityLanguage];
|
|
|
|
// Try to put it in entities hand
|
|
if (_hands.TryPickupAnyHand(uid, translator, false, false, false))
|
|
return true;
|
|
|
|
// Try to find a valid clothing slot on the entity and equip the translator there
|
|
if (TryComp<ClothingComponent>(translator, out var clothing)
|
|
&& clothing.Slots != SlotFlags.NONE
|
|
&& _inventory.TryGetSlots(uid, out var slots)
|
|
&& slots.Any(it => _inventory.TryEquip(uid, translator, it.Name, true, false)))
|
|
return true;
|
|
|
|
// Try to put the translator into entities bag, if it has one
|
|
if (_inventory.TryGetSlotEntity(uid, "back", out var bag)
|
|
&& TryComp<StorageComponent>(bag, out var storage)
|
|
&& _storage.Insert(bag.Value, translator, out _, null, storage, false, false))
|
|
return true;
|
|
|
|
// If all of the above has failed, just drop it at the same location as the entity
|
|
// This should ideally never happen, but who knows.
|
|
Transform(translator).Coordinates = Transform(uid).Coordinates;
|
|
|
|
return true;
|
|
}
|
|
}
|