From 4d47562ddeec41e10ba4a09a726ad1d1ec9d16a3 Mon Sep 17 00:00:00 2001 From: Slava0135 <40753025+Slava0135@users.noreply.github.com> Date: Sat, 6 May 2023 04:38:09 +0300 Subject: [PATCH] Emp more effects (#14550) Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- Content.Client/Emp/EmpSystem.cs | 24 ++++++ .../Effects/ElectricityAnomalySystem.cs | 2 +- Content.Server/Emp/EmpOnTriggerComponent.cs | 6 ++ Content.Server/Emp/EmpSystem.cs | 80 +++++++++++++++++-- .../Light/EntitySystems/PoweredLightSystem.cs | 11 +-- .../Power/EntitySystems/ApcSystem.cs | 13 +++ .../Radio/EntitySystems/HeadsetSystem.cs | 12 +++ .../Radio/EntitySystems/RadioSystem.cs | 2 + .../Systems/SurveillanceCameraSystem.cs | 26 ++++++ .../VendingMachines/VendingMachineSystem.cs | 24 ++++++ .../Components/EmpArtifactComponent.cs | 3 + .../Effects/Systems/EmpArtifactSystem.cs | 2 +- .../Components/ElectricityAnomalyComponent.cs | 6 ++ Content.Shared/Emp/EmpDisabledComponent.cs | 27 +++++++ Content.Shared/Emp/SharedEmpSystem.cs | 10 +++ .../VendingMachineComponent.cs | 7 ++ .../en-US/apc/components/apc-component.ftl | 3 +- Resources/Locale/en-US/emp/emp.ftl | 1 + 18 files changed, 245 insertions(+), 14 deletions(-) create mode 100644 Content.Client/Emp/EmpSystem.cs create mode 100644 Content.Shared/Emp/EmpDisabledComponent.cs create mode 100644 Content.Shared/Emp/SharedEmpSystem.cs create mode 100644 Resources/Locale/en-US/emp/emp.ftl diff --git a/Content.Client/Emp/EmpSystem.cs b/Content.Client/Emp/EmpSystem.cs new file mode 100644 index 0000000000..5ed1022750 --- /dev/null +++ b/Content.Client/Emp/EmpSystem.cs @@ -0,0 +1,24 @@ +using Content.Shared.Emp; +using Robust.Shared.Random; + +namespace Content.Client.Emp; + +public sealed class EmpSystem : SharedEmpSystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var transform)) + { + if (Timing.CurTime > comp.TargetTime) + { + comp.TargetTime = Timing.CurTime + _random.NextFloat(0.8f, 1.2f) * TimeSpan.FromSeconds(comp.EffectCooldown); + Spawn(EmpDisabledEffectPrototype, transform.Coordinates); + } + } + } +} diff --git a/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs b/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs index 89a6361635..0302c62f00 100644 --- a/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs @@ -59,7 +59,7 @@ public sealed class ElectricityAnomalySystem : EntitySystem } var empRange = component.MaxElectrocuteRange * 3; - _emp.EmpPulse(Transform(uid).MapPosition, empRange, component.EmpEnergyConsumption); + _emp.EmpPulse(Transform(uid).MapPosition, empRange, component.EmpEnergyConsumption, component.EmpDisabledDuration); } public override void Update(float frameTime) diff --git a/Content.Server/Emp/EmpOnTriggerComponent.cs b/Content.Server/Emp/EmpOnTriggerComponent.cs index 89bb0fe131..b64c34cecf 100644 --- a/Content.Server/Emp/EmpOnTriggerComponent.cs +++ b/Content.Server/Emp/EmpOnTriggerComponent.cs @@ -15,4 +15,10 @@ public sealed class EmpOnTriggerComponent : Component /// [DataField("energyConsumption"), ViewVariables(VVAccess.ReadWrite)] public float EnergyConsumption; + + /// + /// How long it disables targets in seconds + /// + [DataField("disableDuration"), ViewVariables(VVAccess.ReadWrite)] + public float DisableDuration = 60f; } diff --git a/Content.Server/Emp/EmpSystem.cs b/Content.Server/Emp/EmpSystem.cs index 2f348e4023..b327f086db 100644 --- a/Content.Server/Emp/EmpSystem.cs +++ b/Content.Server/Emp/EmpSystem.cs @@ -1,39 +1,107 @@ using Content.Server.Explosion.EntitySystems; +using Content.Server.Power.EntitySystems; +using Content.Server.Radio; +using Content.Server.SurveillanceCamera; +using Content.Shared.Emp; +using Content.Shared.Examine; using Robust.Shared.Map; namespace Content.Server.Emp; -public sealed class EmpSystem : EntitySystem +public sealed class EmpSystem : SharedEmpSystem { [Dependency] private readonly EntityLookupSystem _lookup = default!; public const string EmpPulseEffectPrototype = "EffectEmpPulse"; - public const string EmpDisabledEffectPrototype = "EffectEmpDisabled"; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnUnpaused); + SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(HandleEmpTrigger); + + SubscribeLocalEvent(OnRadioSendAttempt); + SubscribeLocalEvent(OnRadioReceiveAttempt); + SubscribeLocalEvent(OnApcToggleMainBreaker); + SubscribeLocalEvent(OnCameraSetActive); } - public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption) + public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration) { foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) { - var ev = new EmpPulseEvent(energyConsumption, false); + var ev = new EmpPulseEvent(energyConsumption, false, false); RaiseLocalEvent(uid, ref ev); if (ev.Affected) + { Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates); + } + if (ev.Disabled) + { + var disabled = EnsureComp(uid); + disabled.DisabledUntil = Timing.CurTime + TimeSpan.FromSeconds(duration); + } } Spawn(EmpPulseEffectPrototype, coordinates); } + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.DisabledUntil < Timing.CurTime) + { + RemComp(uid); + var ev = new EmpDisabledRemoved(); + RaiseLocalEvent(uid, ref ev); + } + } + } + + private void OnUnpaused(EntityUid uid, EmpDisabledComponent component, ref EntityUnpausedEvent args) + { + component.DisabledUntil += args.PausedTime; + component.TargetTime += args.PausedTime; + } + + private void OnExamine(EntityUid uid, EmpDisabledComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine")); + } + private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args) { - EmpPulse(Transform(uid).MapPosition, comp.Range, comp.EnergyConsumption); + EmpPulse(Transform(uid).MapPosition, comp.Range, comp.EnergyConsumption, comp.DisableDuration); args.Handled = true; } + + private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnRadioReceiveAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioReceiveAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnApcToggleMainBreaker(EntityUid uid, EmpDisabledComponent component, ref ApcToggleMainBreakerAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnCameraSetActive(EntityUid uid, EmpDisabledComponent component, ref SurveillanceCameraSetActiveAttemptEvent args) + { + args.Cancelled = true; + } } [ByRefEvent] -public record struct EmpPulseEvent(float EnergyConsumption, bool Affected); +public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled); + +[ByRefEvent] +public record struct EmpDisabledRemoved(); diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index 38632912a4..81e4998507 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -224,19 +224,20 @@ namespace Content.Server.Light.EntitySystems /// /// Try to break bulb inside light fixture /// - public void TryDestroyBulb(EntityUid uid, PoweredLightComponent? light = null) + public bool TryDestroyBulb(EntityUid uid, PoweredLightComponent? light = null) { // check bulb state var bulbUid = GetBulb(uid, light); if (bulbUid == null || !EntityManager.TryGetComponent(bulbUid.Value, out LightBulbComponent? lightBulb)) - return; + return false; if (lightBulb.State == LightBulbState.Broken) - return; + return false; // break it _bulbSystem.SetState(bulbUid.Value, LightBulbState.Broken, lightBulb); _bulbSystem.PlayBreakSound(bulbUid.Value, lightBulb); UpdateLight(uid, light); + return true; } #endregion @@ -428,8 +429,8 @@ namespace Content.Server.Light.EntitySystems private void OnEmpPulse(EntityUid uid, PoweredLightComponent component, ref EmpPulseEvent args) { - args.Affected = true; - TryDestroyBulb(uid, component); + if (TryDestroyBulb(uid, component)) + args.Affected = true; } } } diff --git a/Content.Server/Power/EntitySystems/ApcSystem.cs b/Content.Server/Power/EntitySystems/ApcSystem.cs index a5516d9e15..db07eb7aa9 100644 --- a/Content.Server/Power/EntitySystems/ApcSystem.cs +++ b/Content.Server/Power/EntitySystems/ApcSystem.cs @@ -69,6 +69,15 @@ namespace Content.Server.Power.EntitySystems } private void OnToggleMainBreaker(EntityUid uid, ApcComponent component, ApcToggleMainBreakerMessage args) { + var attemptEv = new ApcToggleMainBreakerAttemptEvent(); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + { + _popup.PopupCursor(Loc.GetString("apc-component-on-toggle-cancel"), + args.Session, PopupType.Medium); + return; + } + TryComp(uid, out var access); if (args.Session.AttachedEntity == null) return; @@ -183,8 +192,12 @@ namespace Content.Server.Power.EntitySystems if (component.MainBreakerEnabled) { args.Affected = true; + args.Disabled = true; ApcToggleBreaker(uid, component); } } } + + [ByRefEvent] + public record struct ApcToggleMainBreakerAttemptEvent(bool Cancelled); } diff --git a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs index 4f7ab752c8..c84d28b450 100644 --- a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs +++ b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Chat.Systems; +using Content.Server.Emp; using Content.Server.Radio.Components; using Content.Shared.Inventory.Events; using Content.Shared.Radio; @@ -21,6 +22,8 @@ public sealed class HeadsetSystem : SharedHeadsetSystem SubscribeLocalEvent(OnKeysChanged); SubscribeLocalEvent(OnSpeak); + + SubscribeLocalEvent(OnEmpPulse); } private void OnKeysChanged(EntityUid uid, HeadsetComponent component, EncryptionChannelsChangedEvent args) @@ -98,4 +101,13 @@ public sealed class HeadsetSystem : SharedHeadsetSystem if (TryComp(Transform(uid).ParentUid, out ActorComponent? actor)) _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.ConnectedClient); } + + private void OnEmpPulse(EntityUid uid, HeadsetComponent component, ref EmpPulseEvent args) + { + if (component.Enabled) + { + args.Affected = true; + args.Disabled = true; + } + } } diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index e7e159b2de..b5ced6637e 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -80,6 +80,7 @@ public sealed class RadioSystem : EntitySystem var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource); RaiseLocalEvent(ref sendAttemptEv); + RaiseLocalEvent(radioSource, ref sendAttemptEv); var canSend = !sendAttemptEv.Cancelled; var sourceMapId = Transform(radioSource).MapID; @@ -105,6 +106,7 @@ public sealed class RadioSystem : EntitySystem // check if message can be sent to specific receiver var attemptEv = new RadioReceiveAttemptEvent(channel, radioSource, receiver); RaiseLocalEvent(ref attemptEv); + RaiseLocalEvent(receiver, ref attemptEv); if (attemptEv.Cancelled) continue; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index acb55c36b6..32bb567678 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -1,6 +1,7 @@ using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; +using Content.Server.Emp; using Content.Server.Power.Components; using Content.Shared.ActionBlocker; using Content.Shared.DeviceNetwork; @@ -57,6 +58,9 @@ public sealed class SurveillanceCameraSystem : EntitySystem SubscribeLocalEvent(OnSetName); SubscribeLocalEvent(OnSetNetwork); SubscribeLocalEvent>(AddVerbs); + + SubscribeLocalEvent(OnEmpPulse); + SubscribeLocalEvent(OnEmpDisabledRemoved); } private void OnPacketReceived(EntityUid uid, SurveillanceCameraComponent component, DeviceNetworkPacketEvent args) @@ -271,6 +275,10 @@ public sealed class SurveillanceCameraSystem : EntitySystem if (setting) { + var attemptEv = new SurveillanceCameraSetActiveAttemptEvent(); + RaiseLocalEvent(camera, ref attemptEv); + if (attemptEv.Cancelled) + return; component.Active = setting; } else @@ -392,6 +400,21 @@ public sealed class SurveillanceCameraSystem : EntitySystem _appearance.SetData(uid, SurveillanceCameraVisualsKey.Key, key, appearance); } + + private void OnEmpPulse(EntityUid uid, SurveillanceCameraComponent component, ref EmpPulseEvent args) + { + if (component.Active) + { + args.Affected = true; + args.Disabled = true; + SetActive(uid, false); + } + } + + private void OnEmpDisabledRemoved(EntityUid uid, SurveillanceCameraComponent component, ref EmpDisabledRemoved args) + { + SetActive(uid, true); + } } public sealed class OnSurveillanceCameraViewerAddEvent : EntityEventArgs @@ -414,3 +437,6 @@ public sealed class SurveillanceCameraDeactivateEvent : EntityEventArgs Camera = camera; } } + +[ByRefEvent] +public record struct SurveillanceCameraSetActiveAttemptEvent(bool Cancelled); diff --git a/Content.Server/VendingMachines/VendingMachineSystem.cs b/Content.Server/VendingMachines/VendingMachineSystem.cs index 2f31da2cd4..9d8c6d98f5 100644 --- a/Content.Server/VendingMachines/VendingMachineSystem.cs +++ b/Content.Server/VendingMachines/VendingMachineSystem.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Server.Cargo.Systems; +using Content.Server.Emp; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.UserInterface; @@ -12,6 +13,7 @@ using Content.Shared.Destructible; using Content.Shared.DoAfter; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; +using Content.Shared.Emp; using Content.Shared.Popups; using Content.Shared.Throwing; using Content.Shared.VendingMachines; @@ -19,6 +21,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Server.VendingMachines { @@ -31,6 +34,7 @@ namespace Content.Server.VendingMachines [Dependency] private readonly PricingSystem _pricing = default!; [Dependency] private readonly ThrowingSystem _throwingSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; private ISawmill _sawmill = default!; @@ -44,6 +48,7 @@ namespace Content.Server.VendingMachines SubscribeLocalEvent(OnEmagged); SubscribeLocalEvent(OnDamage); SubscribeLocalEvent(OnVendingPrice); + SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnActivatableUIOpenAttempt); SubscribeLocalEvent(OnBoundUIOpened); @@ -437,6 +442,15 @@ namespace Content.Server.VendingMachines } } } + var disabled = EntityQueryEnumerator(); + while (disabled.MoveNext(out var uid, out _, out var comp)) + { + if (comp.NextEmpEject < _timing.CurTime) + { + EjectRandom(uid, true, false, comp); + comp.NextEmpEject += TimeSpan.FromSeconds(5 * comp.EjectDelay); + } + } } public void TryRestockInventory(EntityUid uid, VendingMachineComponent? vendComponent = null) @@ -473,5 +487,15 @@ namespace Content.Server.VendingMachines args.Price += priceSets.Max(); } + + private void OnEmpPulse(EntityUid uid, VendingMachineComponent component, ref EmpPulseEvent args) + { + if (!component.Broken && this.IsPowered(uid, EntityManager)) + { + args.Affected = true; + args.Disabled = true; + component.NextEmpEject = _timing.CurTime; + } + } } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/EmpArtifactComponent.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/EmpArtifactComponent.cs index dc37782a52..cea776f05d 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/EmpArtifactComponent.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/EmpArtifactComponent.cs @@ -14,4 +14,7 @@ public sealed class EmpArtifactComponent : Component [DataField("energyConsumption"), ViewVariables(VVAccess.ReadWrite)] public float EnergyConsumption = 1000000; + + [DataField("disableDuration"), ViewVariables(VVAccess.ReadWrite)] + public float DisableDuration = 60f; } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/EmpArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/EmpArtifactSystem.cs index c4346b51bc..d4ed8272aa 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/EmpArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/EmpArtifactSystem.cs @@ -16,6 +16,6 @@ public sealed class EmpArtifactSystem : EntitySystem private void OnActivate(EntityUid uid, EmpArtifactComponent component, ArtifactActivatedEvent args) { - _emp.EmpPulse(Transform(uid).MapPosition, component.Range, component.EnergyConsumption); + _emp.EmpPulse(Transform(uid).MapPosition, component.Range, component.EnergyConsumption, component.DisableDuration); } } \ No newline at end of file diff --git a/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs index 8da6dd4c42..06d03f1019 100644 --- a/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs +++ b/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs @@ -44,4 +44,10 @@ public sealed class ElectricityAnomalyComponent : Component /// [DataField("empEnergyConsumption"), ViewVariables(VVAccess.ReadWrite)] public float EmpEnergyConsumption = 100000f; + + /// + /// Duration of devices being disabled by the emp pulse upon going supercritical. + /// + [DataField("empDisabledDuration"), ViewVariables(VVAccess.ReadWrite)] + public float EmpDisabledDuration = 60f; } diff --git a/Content.Shared/Emp/EmpDisabledComponent.cs b/Content.Shared/Emp/EmpDisabledComponent.cs new file mode 100644 index 0000000000..c84bab9d4d --- /dev/null +++ b/Content.Shared/Emp/EmpDisabledComponent.cs @@ -0,0 +1,27 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Emp; + +/// +/// While entity has this component it is "disabled" by EMP. +/// Add desired behaviour in other systems +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedEmpSystem))] +public sealed class EmpDisabledComponent : Component +{ + /// + /// Moment of time when component is removed and entity stops being "disabled" + /// + [DataField("timeLeft", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan DisabledUntil; + + [DataField("effectCoolDown"), ViewVariables(VVAccess.ReadWrite)] + public float EffectCooldown = 3f; + + /// + /// When next effect will be spawned + /// + public TimeSpan TargetTime = TimeSpan.Zero; +} diff --git a/Content.Shared/Emp/SharedEmpSystem.cs b/Content.Shared/Emp/SharedEmpSystem.cs new file mode 100644 index 0000000000..6e4478bb6d --- /dev/null +++ b/Content.Shared/Emp/SharedEmpSystem.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Timing; + +namespace Content.Shared.Emp; + +public abstract class SharedEmpSystem : EntitySystem +{ + [Dependency] protected readonly IGameTiming Timing = default!; + + protected const string EmpDisabledEffectPrototype = "EffectEmpDisabled"; +} diff --git a/Content.Shared/VendingMachines/VendingMachineComponent.cs b/Content.Shared/VendingMachines/VendingMachineComponent.cs index 85e1178d46..b648d36f4e 100644 --- a/Content.Shared/VendingMachines/VendingMachineComponent.cs +++ b/Content.Shared/VendingMachines/VendingMachineComponent.cs @@ -3,6 +3,7 @@ using Content.Shared.Actions.ActionTypes; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.VendingMachines @@ -115,6 +116,12 @@ namespace Content.Shared.VendingMachines public float DenyAccumulator = 0f; public float DispenseOnHitAccumulator = 0f; + /// + /// While disabled by EMP it randomly ejects items + /// + [DataField("nextEmpEject", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextEmpEject = TimeSpan.Zero; + #region Client Visuals /// /// RSI state for when the vending machine is unpowered. diff --git a/Resources/Locale/en-US/apc/components/apc-component.ftl b/Resources/Locale/en-US/apc/components/apc-component.ftl index d180bcbe06..6e152adb1d 100644 --- a/Resources/Locale/en-US/apc/components/apc-component.ftl +++ b/Resources/Locale/en-US/apc/components/apc-component.ftl @@ -1,3 +1,4 @@ apc-component-insufficient-access = Insufficient access! apc-component-on-examine-panel-open = The [color=lightgray]APC electronics panel[/color] is [color=red]open[/color]. -apc-component-on-examine-panel-closed = The [color=lightgray]APC electronics panel[/color] is [color=darkgreen]closed[/color]. \ No newline at end of file +apc-component-on-examine-panel-closed = The [color=lightgray]APC electronics panel[/color] is [color=darkgreen]closed[/color]. +apc-component-on-toggle-cancel = It does nothing! diff --git a/Resources/Locale/en-US/emp/emp.ftl b/Resources/Locale/en-US/emp/emp.ftl new file mode 100644 index 0000000000..6d5e790bef --- /dev/null +++ b/Resources/Locale/en-US/emp/emp.ftl @@ -0,0 +1 @@ +emp-disabled-comp-on-examine = [color=lightblue]It's disrupted by an electric field... [/color]