Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/real-ee/master' into feat/…
Browse files Browse the repository at this point in the history
…floof-upstream-merge-2024-09-05
  • Loading branch information
Mnemotechnician committed Sep 8, 2024
2 parents e4686d0 + 01c94a1 commit 51506c3
Show file tree
Hide file tree
Showing 18 changed files with 231 additions and 121 deletions.
152 changes: 53 additions & 99 deletions Content.Server/Language/TranslatorSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
using Content.Shared.Language.Systems;
using Content.Shared.PowerCell;
using Content.Shared.Language.Components.Translators;
using Robust.Shared.Containers;

namespace Content.Server.Language;

// This does not support holding multiple translators at once.
// That shouldn't be an issue for now, but it needs to be fixed later.
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!;
Expand All @@ -24,65 +24,64 @@ public override void Initialize()
base.Initialize();

SubscribeLocalEvent<IntrinsicTranslatorComponent, DetermineEntityLanguagesEvent>(OnDetermineLanguages);
SubscribeLocalEvent<HoldsTranslatorComponent, DetermineEntityLanguagesEvent>(OnDetermineLanguages);
SubscribeLocalEvent<ImplantedTranslatorComponent, DetermineEntityLanguagesEvent>(OnDetermineLanguages);
SubscribeLocalEvent<HoldsTranslatorComponent, DetermineEntityLanguagesEvent>(OnProxyDetermineLanguages);

SubscribeLocalEvent<HandheldTranslatorComponent, EntGotInsertedIntoContainerMessage>(OnTranslatorInserted);
SubscribeLocalEvent<HandheldTranslatorComponent, EntGotRemovedFromContainerMessage>(OnTranslatorRemoved);
SubscribeLocalEvent<HandheldTranslatorComponent, ActivateInWorldEvent>(OnTranslatorToggle);
SubscribeLocalEvent<HandheldTranslatorComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);

SubscribeLocalEvent<HandheldTranslatorComponent, InteractHandEvent>(OnTranslatorInteract);
SubscribeLocalEvent<HandheldTranslatorComponent, DroppedEvent>(OnTranslatorDropped);
}

private void OnDetermineLanguages(EntityUid uid, IntrinsicTranslatorComponent component, DetermineEntityLanguagesEvent ev)
{
if (!component.Enabled || !TryComp<LanguageSpeakerComponent>(uid, out var speaker))
if (!component.Enabled
|| component.LifeStage >= ComponentLifeStage.Removing
|| !TryComp<LanguageKnowledgeComponent>(uid, out var knowledge)
|| !_powerCell.HasActivatableCharge(uid))
return;

if (!_powerCell.HasActivatableCharge(uid))
CopyLanguages(component, ev, knowledge);
}

private void OnProxyDetermineLanguages(EntityUid uid, HoldsTranslatorComponent component, DetermineEntityLanguagesEvent ev)
{
if (!TryComp<LanguageKnowledgeComponent>(uid, out var knowledge))
return;

// The idea here is as follows:
// Required languages are languages that are required to operate the translator.
// The translator has a limited number of languages it can translate to and translate from.
// If the wielder understands the language of the translator, they will be able to understand translations provided by it
// If the wielder also speaks that language, they will be able to use it to translate their own speech by "speaking" in that language
var addSpoken = CheckLanguagesMatch(component.RequiredLanguages, speaker.SpokenLanguages, component.RequiresAllLanguages);
var addUnderstood = CheckLanguagesMatch(component.RequiredLanguages, speaker.UnderstoodLanguages, component.RequiresAllLanguages);
foreach (var (translator, translatorComp) in component.Translators.ToArray())
{
if (!translatorComp.Enabled || !_powerCell.HasActivatableCharge(uid))
continue;

if (addSpoken)
foreach (var language in component.SpokenLanguages)
ev.SpokenLanguages.Add(language);
if (!_containers.TryGetContainingContainer(translator, out var container) || container.Owner != uid)
{
component.Translators.RemoveWhere(it => it.Owner == translator);
continue;
}

if (addUnderstood)
foreach (var language in component.UnderstoodLanguages)
ev.UnderstoodLanguages.Add(language);
CopyLanguages(translatorComp, ev, knowledge);
}
}

private void OnTranslatorInteract(EntityUid translator, HandheldTranslatorComponent component, InteractHandEvent args)
private void OnTranslatorInserted(EntityUid translator, HandheldTranslatorComponent component, EntGotInsertedIntoContainerMessage args)
{
var holder = args.User;
if (!EntityManager.HasComponent<LanguageSpeakerComponent>(holder))
if (args.Container.Owner is not {Valid: true} holder
|| !EntityManager.HasComponent<LanguageSpeakerComponent>(holder))
return;

var intrinsic = EnsureComp<HoldsTranslatorComponent>(holder);
UpdateBoundIntrinsicComp(component, intrinsic, component.Enabled);
intrinsic.Translators.Add((translator, component));

_language.UpdateEntityLanguages(holder);
}

private void OnTranslatorDropped(EntityUid translator, HandheldTranslatorComponent component, DroppedEvent args)
private void OnTranslatorRemoved(EntityUid translator, HandheldTranslatorComponent component, EntGotRemovedFromContainerMessage args)
{
var holder = args.User;
if (!EntityManager.TryGetComponent<HoldsTranslatorComponent>(holder, out var intrinsic))
if (args.Container.Owner is not {Valid: true} holder
|| !EntityManager.TryGetComponent<HoldsTranslatorComponent>(holder, out var intrinsic))
return;

if (intrinsic.Issuer == component)
{
intrinsic.Enabled = false;
RemCompDeferred(holder, intrinsic);
}

intrinsic.Translators.RemoveWhere(it => it.Owner == translator);
_language.UpdateEntityLanguages(holder);
}

Expand All @@ -93,53 +92,31 @@ private void OnTranslatorToggle(EntityUid translator, HandheldTranslatorComponen

// This will show a popup if false
var hasPower = _powerCell.HasDrawCharge(translator);
var isEnabled = !translatorComp.Enabled && hasPower;

if (Transform(args.Target).ParentUid is { Valid: true } holder
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))
{
// 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 = EnsureComp<HoldsTranslatorComponent>(holder);
var isEnabled = !translatorComp.Enabled;
if (intrinsic.Issuer != translatorComp)
{
// The intrinsic comp wasn't owned by this handheld translator, so this wasn't the active translator.
// Thus, the intrinsic comp needs to be turned on regardless of its previous state.
intrinsic.Issuer = translatorComp;
isEnabled = true;
}
isEnabled &= hasPower;

UpdateBoundIntrinsicComp(translatorComp, intrinsic, isEnabled);
translatorComp.Enabled = isEnabled;
_powerCell.SetPowerCellDrawEnabled(translator, isEnabled);

// The first new spoken language added by this translator, or null
var firstNewLanguage = translatorComp.SpokenLanguages.FirstOrDefault(it => !languageComp.SpokenLanguages.Contains(it));

_language.UpdateEntityLanguages(holder, languageComp);

// Update the current language of the entity if necessary
if (isEnabled && translatorComp.SetLanguageOnInteract && firstNewLanguage is {})
_language.SetLanguage(holder, firstNewLanguage, languageComp);
}
else
{
// This is a standalone translator (e.g. lying on the ground), toggle its state.
translatorComp.Enabled = !translatorComp.Enabled && hasPower;
_powerCell.SetPowerCellDrawEnabled(translator, !translatorComp.Enabled && hasPower);
}

OnAppearanceChange(translator, translatorComp);

if (hasPower)
{
var message = Loc.GetString(
translatorComp.Enabled
? "translator-component-turnon"
: "translator-component-shutoff",
("translator", translatorComp.Owner));
_popup.PopupEntity(message, translatorComp.Owner, args.User);
var loc = isEnabled ? "translator-component-turnon" : "translator-component-shutoff";
var message = Loc.GetString(loc, ("translator", translator));
_popup.PopupEntity(message, translator, args.User);
}
}

Expand All @@ -148,43 +125,20 @@ private void OnPowerCellSlotEmpty(EntityUid translator, HandheldTranslatorCompon
component.Enabled = false;
_powerCell.SetPowerCellDrawEnabled(translator, false);
OnAppearanceChange(translator, component);

if (Transform(translator).ParentUid is { Valid: true } holder
&& TryComp<LanguageSpeakerComponent>(holder, out var languageComp))
{
if (!EntityManager.TryGetComponent<HoldsTranslatorComponent>(holder, out var intrinsic))
return;

if (intrinsic.Issuer == component)
{
intrinsic.Enabled = false;
RemComp(holder, intrinsic);
}

_language.UpdateEntityLanguages(holder, languageComp);
}
}

/// <summary>
/// Copies the state from the handheld to the intrinsic component
/// </summary>
private void UpdateBoundIntrinsicComp(HandheldTranslatorComponent comp, HoldsTranslatorComponent intrinsic, bool isEnabled)
private void CopyLanguages(BaseTranslatorComponent from, DetermineEntityLanguagesEvent to, LanguageKnowledgeComponent knowledge)
{
if (isEnabled)
{
intrinsic.SpokenLanguages = [..comp.SpokenLanguages];
intrinsic.UnderstoodLanguages = [..comp.UnderstoodLanguages];
intrinsic.RequiredLanguages = [..comp.RequiredLanguages];
}
else
{
intrinsic.SpokenLanguages.Clear();
intrinsic.UnderstoodLanguages.Clear();
intrinsic.RequiredLanguages.Clear();
}
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);

intrinsic.Enabled = isEnabled;
intrinsic.Issuer = comp;
if (addUnderstood)
foreach (var language in from.UnderstoodLanguages)
to.UnderstoodLanguages.Add(language);
}

/// <summary>
Expand Down
38 changes: 38 additions & 0 deletions Content.Server/Psionics/PsionicsCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
using Content.Shared.Abilities.Psionics;
using Robust.Shared.Console;
using Robust.Shared.Player;
using Content.Server.Abilities.Psionics;
using Robust.Shared.Prototypes;
using Content.Shared.Psionics;

namespace Content.Server.Psionics;

Expand All @@ -25,3 +28,38 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args)
}
}
}

[AdminCommand(AdminFlags.Fun)]
public sealed class AddPsionicPowerCommand : IConsoleCommand
{
public string Command => "addpsionicpower";
public string Description => Loc.GetString("command-addpsionicpower-description");
public string Help => Loc.GetString("command-addpsionicpower-help");
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var entMan = IoCManager.Resolve<IEntityManager>();
var psionicPowers = IoCManager.Resolve<PsionicAbilitiesSystem>();
var protoMan = IoCManager.Resolve<IPrototypeManager>();

if (args.Length != 2)
{
shell.WriteError(Loc.GetString("shell-need-exactly-one-argument"));
return;
}

if (!EntityUid.TryParse(args[0], out var uid))
{
shell.WriteError(Loc.GetString("addpsionicpower-args-one-error"));
return;
}

if (!protoMan.TryIndex<PsionicPowerPrototype>(args[1], out var powerProto))
{
shell.WriteError(Loc.GetString("addpsionicpower-args-two-error"));
return;
}

entMan.EnsureComponent<PsionicComponent>(uid, out var psionic);
psionicPowers.InitializePsionicPower(uid, powerProto, psionic);
}
}
10 changes: 10 additions & 0 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2548,5 +2548,15 @@ public static readonly CVarDef<float>
CVarDef.Create("mood.decreases_speed", true, CVar.SERVER);

#endregion

#region Material Reclaimer

/// <summary>
/// Whether or not a Material Reclaimer is allowed to eat people when emagged.
/// </summary>
public static readonly CVarDef<bool> ReclaimerAllowGibbing =
CVarDef.Create("reclaimer.allow_gibbing", true, CVar.SERVER);

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Content.Shared.Language.Components.Translators;

/// <summary>
/// Applied internally to the holder of [HandheldTranslatorComponent].
/// Do not use directly. Use [HandheldTranslatorComponent] instead.
/// Applied internally to the holder of an entity with [HandheldTranslatorComponent].
/// </summary>
[RegisterComponent]
public sealed partial class HoldsTranslatorComponent : IntrinsicTranslatorComponent
public sealed partial class HoldsTranslatorComponent : Component
{
public Component? Issuer = null;
[NonSerialized]
public HashSet<Entity<HandheldTranslatorComponent>> Translators = new();
}

This file was deleted.

17 changes: 10 additions & 7 deletions Content.Shared/Materials/SharedMaterialReclaimerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Content.Shared.Administration.Logs;
using Content.Shared.Audio;
using Content.Shared.Body.Components;
using Content.Shared.CCVar;
using Content.Shared.Coordinates;
using Content.Shared.Database;
using Content.Shared.Emag.Components;
Expand All @@ -11,6 +12,7 @@
using Content.Shared.Stacks;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Physics.Events;
Expand All @@ -29,6 +31,7 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem
[Dependency] protected readonly SharedAmbientSoundSystem AmbientSound = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] protected readonly SharedContainerSystem Container = default!;
[Dependency] private readonly IConfigurationManager _config = default!;

public const string ActiveReclaimerContainerId = "active-material-reclaimer-container";

Expand Down Expand Up @@ -193,16 +196,16 @@ public bool CanStart(EntityUid uid, MaterialReclaimerComponent component)
}

/// <summary>
/// Whether or not the reclaimer satisfies the conditions
/// allowing it to gib/reclaim a living creature.
/// Whether or not the reclaimer satisfies the conditions
/// allowing it to gib/reclaim a living creature.
/// </summary>
public bool CanGib(EntityUid uid, EntityUid victim, MaterialReclaimerComponent component)
{
return false; // DeltaV - Kinda LRP
// return component.Powered &&
// component.Enabled &&
// HasComp<BodyComponent>(victim) &&
// HasComp<EmaggedComponent>(uid);
return _config.GetCVar(CCVars.ReclaimerAllowGibbing)
&& component.Powered
&& component.Enabled
&& HasComp<BodyComponent>(victim)
&& HasComp<EmaggedComponent>(uid);
}

/// <summary>
Expand Down
Binary file added Resources/Audio/Admin/adminhelp_old.ogg
Binary file not shown.
Loading

0 comments on commit 51506c3

Please sign in to comment.