diff --git a/Content.Server/Anomaly/AnomalySynchronizerSystem.cs b/Content.Server/Anomaly/AnomalySynchronizerSystem.cs
new file mode 100644
index 0000000000..6e881aa3d1
--- /dev/null
+++ b/Content.Server/Anomaly/AnomalySynchronizerSystem.cs
@@ -0,0 +1,148 @@
+using Content.Server.Anomaly.Components;
+using Content.Server.DeviceLinking.Systems;
+using Content.Server.Power.Components;
+using Content.Server.Power.EntitySystems;
+using Content.Shared.Anomaly.Components;
+using Content.Shared.Interaction;
+using Content.Shared.Popups;
+
+namespace Content.Server.Anomaly;
+
+///
+/// a device that allows you to translate anomaly activity into multitool signals.
+///
+public sealed partial class AnomalySynchronizerSystem : EntitySystem
+{
+ [Dependency] private readonly AnomalySystem _anomaly = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
+ [Dependency] private readonly DeviceLinkSystem _signal = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly PowerReceiverSystem _power = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnInteractHand);
+ SubscribeLocalEvent(OnPowerChanged);
+
+ SubscribeLocalEvent(OnAnomalyPulse);
+ SubscribeLocalEvent(OnAnomalySeverityChanged);
+ SubscribeLocalEvent(OnAnomalyStabilityChanged);
+ }
+
+ private void OnPowerChanged(EntityUid uid, AnomalySynchronizerComponent component, ref PowerChangedEvent args)
+ {
+ if (args.Powered)
+ return;
+
+ if (!TryComp(component.ConnectedAnomaly, out var anomaly))
+ return;
+
+ _anomaly.DoAnomalyPulse(component.ConnectedAnomaly.Value, anomaly);
+ DisconneсtFromAnomaly(uid, component, anomaly);
+ }
+
+ private void OnInteractHand(EntityUid uid, AnomalySynchronizerComponent component, InteractHandEvent args)
+ {
+ if (!_power.IsPowered(uid))
+ return;
+
+ foreach (var entity in _entityLookup.GetEntitiesInRange(uid, 0.15f)) //is the radius of one tile. It must not be set higher, otherwise the anomaly can be moved from tile to tile
+ {
+ if (!TryComp(entity, out var anomaly))
+ continue;
+
+
+ ConnectToAnomaly(uid, component, entity, anomaly);
+ break;
+ }
+ }
+
+ private void ConnectToAnomaly(EntityUid uid, AnomalySynchronizerComponent component, EntityUid auid, AnomalyComponent anomaly)
+ {
+ if (component.ConnectedAnomaly == auid)
+ return;
+
+ component.ConnectedAnomaly = auid;
+ //move the anomaly to the center of the synchronizer, for aesthetics.
+ var targetXform = _transform.GetWorldPosition(uid);
+ _transform.SetWorldPosition(auid, targetXform);
+
+ _anomaly.DoAnomalyPulse(component.ConnectedAnomaly.Value, anomaly);
+ _popup.PopupEntity(Loc.GetString("anomaly-sync-connected"), uid, PopupType.Medium);
+ _audio.PlayPvs(component.ConnectedSound, uid);
+ }
+
+ //TO DO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
+ //Currently only bluespace anomaly can do this, but for some reason it is the only one that cannot be connected to the synchronizer.
+ private void DisconneсtFromAnomaly(EntityUid uid, AnomalySynchronizerComponent component, AnomalyComponent anomaly)
+ {
+ if (component.ConnectedAnomaly == null)
+ return;
+
+ _anomaly.DoAnomalyPulse(component.ConnectedAnomaly.Value, anomaly);
+ _popup.PopupEntity(Loc.GetString("anomaly-sync-disconnected"), uid, PopupType.Large);
+ _audio.PlayPvs(component.ConnectedSound, uid);
+
+ component.ConnectedAnomaly = default!;
+ }
+
+ private void OnAnomalyPulse(ref AnomalyPulseEvent args)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var ent, out var component))
+ {
+ if (args.Anomaly != component.ConnectedAnomaly)
+ continue;
+ if (!_power.IsPowered(ent))
+ continue;
+
+ _signal.InvokePort(ent, component.PulsePort);
+ }
+ }
+
+ private void OnAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var ent, out var component))
+ {
+ if (args.Anomaly != component.ConnectedAnomaly)
+ continue;
+ if (!_power.IsPowered(ent))
+ continue;
+ //The superscritical port is invoked not at the AnomalySupercriticalEvent,
+ //but at the moment the growth animation starts. Otherwise, there is no point in this port.
+ //ATTENTION! the console command supercriticalanomaly does not work here,
+ //as it forcefully causes growth to start without increasing severity.
+ if (args.Severity >= 1)
+ _signal.InvokePort(ent, component.SupercritPort);
+ }
+ }
+ private void OnAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var ent, out var component))
+ {
+ if (args.Anomaly != component.ConnectedAnomaly)
+ continue;
+ if (TryComp(ent, out var apcPower) && !apcPower.Powered)
+ continue;
+
+ if (args.Stability < 0.25f) //I couldn't find where these values are stored, so I hardcoded them. Tell me where these variables are stored and I'll fix it
+ {
+ _signal.InvokePort(ent, component.DecayingPort);
+ }
+ else if (args.Stability > 0.5f) //I couldn't find where these values are stored, so I hardcoded them. Tell me where these variables are stored and I'll fix it
+ {
+ _signal.InvokePort(ent, component.GrowingPort);
+ }
+ else
+ {
+ _signal.InvokePort(ent, component.StabilizePort);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs b/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs
new file mode 100644
index 0000000000..295ce885c2
--- /dev/null
+++ b/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs
@@ -0,0 +1,42 @@
+using Content.Shared.Anomaly;
+using Content.Shared.Anomaly.Components;
+using Content.Shared.DeviceLinking;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Anomaly.Components;
+
+///
+/// a device that allows you to translate anomaly activity into multitool signals.
+///
+[RegisterComponent, Access(typeof(AnomalySynchronizerSystem))]
+public sealed partial class AnomalySynchronizerComponent : Component
+{
+ ///
+ /// The uid of the anomaly to which the synchronizer is connected.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public EntityUid? ConnectedAnomaly;
+
+
+ [DataField]
+ public ProtoId DecayingPort = "Decaying";
+
+ [DataField]
+ public ProtoId StabilizePort = "Stabilize";
+
+ [DataField]
+ public ProtoId GrowingPort = "Growing";
+
+ [DataField]
+ public ProtoId PulsePort = "Pulse";
+
+ [DataField]
+ public ProtoId SupercritPort = "Supercritical";
+
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier ConnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg");
+
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier DisconnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg");
+}
diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs
index cf3ba75aaa..a6f4f6c086 100644
--- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs
+++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs
@@ -243,16 +243,17 @@ public sealed partial class AnomalyComponent : Component
///
/// Event raised at regular intervals on an anomaly to do whatever its effect is.
///
+/// The anomaly pulsing
///
///
[ByRefEvent]
-public readonly record struct AnomalyPulseEvent(float Stability, float Severity);
+public readonly record struct AnomalyPulseEvent(EntityUid Anomaly, float Stability, float Severity);
///
/// Event raised on an anomaly when it reaches a supercritical point.
///
[ByRefEvent]
-public readonly record struct AnomalySupercriticalEvent;
+public readonly record struct AnomalySupercriticalEvent(EntityUid Anomaly);
///
/// Event broadcast after an anomaly goes supercritical
diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs
index ca77544a15..48413ac001 100644
--- a/Content.Shared/Anomaly/SharedAnomalySystem.cs
+++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs
@@ -109,9 +109,9 @@ public abstract class SharedAnomalySystem : EntitySystem
var pulse = EnsureComp(uid);
pulse.EndTime = Timing.CurTime + pulse.PulseDuration;
Appearance.SetData(uid, AnomalyVisuals.IsPulsing, true);
-
- var ev = new AnomalyPulseEvent(component.Stability, component.Severity);
- RaiseLocalEvent(uid, ref ev);
+
+ var ev = new AnomalyPulseEvent(uid, component.Stability, component.Severity);
+ RaiseLocalEvent(uid, ref ev, true);
}
///
@@ -154,8 +154,8 @@ public abstract class SharedAnomalySystem : EntitySystem
if (_net.IsServer)
_sawmill.Info($"Raising supercritical event. Entity: {ToPrettyString(uid)}");
- var ev = new AnomalySupercriticalEvent();
- RaiseLocalEvent(uid, ref ev);
+ var ev = new AnomalySupercriticalEvent(uid);
+ RaiseLocalEvent(uid, ref ev, true);
EndAnomaly(uid, component, true);
}
diff --git a/Resources/Audio/Machines/anomaly_sync_connect.ogg b/Resources/Audio/Machines/anomaly_sync_connect.ogg
new file mode 100644
index 0000000000..c718eaf459
Binary files /dev/null and b/Resources/Audio/Machines/anomaly_sync_connect.ogg differ
diff --git a/Resources/Audio/Machines/attributions.yml b/Resources/Audio/Machines/attributions.yml
index bbf4ea9ac0..3fa3aa06d7 100644
--- a/Resources/Audio/Machines/attributions.yml
+++ b/Resources/Audio/Machines/attributions.yml
@@ -46,4 +46,9 @@
- files: ["warning_buzzer.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Taken from TG station."
- source: "https://github.com/tgstation/tgstation/blob/d4f678a1772007ff8d7eddd21cf7218c8e07bfc0/sound/machines/warning-buzzer.ogg"
\ No newline at end of file
+ source: "https://github.com/tgstation/tgstation/blob/d4f678a1772007ff8d7eddd21cf7218c8e07bfc0/sound/machines/warning-buzzer.ogg"
+
+- files: ["anomaly_sync_connect.ogg"]
+ license: "CC0-1.0"
+ copyright: Created by newagesoup, convert to ogg mono by TheShuEd"
+ source: "https://freesound.org/people/newagesoup/sounds/341172/"
\ No newline at end of file
diff --git a/Resources/Locale/en-US/anomaly/anomaly.ftl b/Resources/Locale/en-US/anomaly/anomaly.ftl
index 29d5169694..83b992ce23 100644
--- a/Resources/Locale/en-US/anomaly/anomaly.ftl
+++ b/Resources/Locale/en-US/anomaly/anomaly.ftl
@@ -25,6 +25,9 @@ anomaly-scanner-particle-unstable = - [color=plum]Unstable type:[/color] {$type}
anomaly-scanner-particle-containment = - [color=goldenrod]Containment type:[/color] {$type}
anomaly-scanner-pulse-timer = Time until next pulse: [color=gray]{$time}[/color]
+anomaly-sync-connected = Anomaly successfully attached
+anomaly-sync-disconnected = The connection to the anomaly has been lost!
+
anomaly-generator-ui-title = Anomaly Generator
anomaly-generator-fuel-display = Fuel:
anomaly-generator-cooldown = Cooldown: [color=gray]{$time}[/color]
diff --git a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl
index 154f20eee7..e5f92c5b00 100644
--- a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl
+++ b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl
@@ -45,3 +45,18 @@ signal-port-description-air-warning = This port is invoked with HIGH when in war
signal-port-name-air-normal = Normal
signal-port-description-air-normal = This port is invoked with HIGH when in normal mode and LOW when not.
+
+signal-port-name-decaying = Decaying
+signal-port-description-decaying = This port is invoked when a bound anomaly starts to decay.
+
+signal-port-name-stabilize = Stabilize
+signal-port-description-stabilize = This port is invoked when a bound anomaly is normalized.
+
+signal-port-name-growing = Growing
+signal-port-description-growing = This port is invoked when a bound anomaly starts to grow.
+
+signal-port-name-pulse = Pulse
+signal-port-description-pulse = This port is invoked when a bound anomaly is pulsing.
+
+signal-port-name-supercrit = Supercritical
+signal-port-description-supercrit = This port is invoked when a bound anomaly explode after supercrit state.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl
index 28c7377082..0f8a657aa4 100644
--- a/Resources/Locale/en-US/research/technologies.ftl
+++ b/Resources/Locale/en-US/research/technologies.ftl
@@ -53,7 +53,7 @@ research-technology-advanced-parts = Advanced Parts
research-technology-grappling = Grappling
research-technology-abnormal-artifact-manipulation = Abnormal Artifact Manipulation
research-technology-gravity-manipulation = Gravity Manipulation
-research-technology-mobile-anomaly-tech = Mobile Anomaly Tech
+research-technology-advanced-anomaly-research = Advanced Anomaly Research
research-technology-rped = Rapid Part Exchange
research-technology-super-parts = Super Parts
diff --git a/Resources/Prototypes/DeviceLinking/source_ports.yml b/Resources/Prototypes/DeviceLinking/source_ports.yml
index 73e96978a7..6e97c3c809 100644
--- a/Resources/Prototypes/DeviceLinking/source_ports.yml
+++ b/Resources/Prototypes/DeviceLinking/source_ports.yml
@@ -114,3 +114,28 @@
name: signal-port-name-air-normal
description: signal-port-description-air-normal
defaultLinks: [ DoorBolt ]
+
+- type: sourcePort
+ id: Decaying
+ name: signal-port-name-decaying
+ description: signal-port-description-decaying
+
+- type: sourcePort
+ id: Stabilize
+ name: signal-port-name-stabilize
+ description: signal-port-description-stabilize
+
+- type: sourcePort
+ id: Growing
+ name: signal-port-name-growing
+ description: signal-port-description-growing
+
+- type: sourcePort
+ id: Pulse
+ name: signal-port-name-pulse
+ description: signal-port-description-pulse
+
+- type: sourcePort
+ id: Supercritical
+ name: signal-port-name-supercrit
+ description: signal-port-description-supercrit
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml
index 043bf707b4..3b5d33ee06 100644
--- a/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml
+++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml
@@ -19,3 +19,4 @@
- AnomalyRock
- AnomalyLiquid
chance: 1
+ offset: 0.15 # not to put it higher. The anomaly sychnronizer looks for anomalies within this radius, and if the radius is higher, the anomaly can be attracted from a neighboring tile.
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index a25e5b7069..2aed92bc28 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -233,6 +233,22 @@
Cable: 1
PlasmaGlass: 10
+- type: entity
+ parent: BaseMachineCircuitboard
+ id: AnomalySynchronizerCircuitboard
+ name: anomaly synchronizer machine board
+ description: A machine printed circuit board for an anomaly synchronizer.
+ components:
+ - type: Sprite
+ state: science
+ - type: MachineBoard
+ prototype: MachineAnomalySynchronizer
+ requirements:
+ Manipulator: 2
+ Capacitor: 5
+ materialRequirements:
+ PlasmaGlass: 25
+
- type: entity
parent: BaseMachineCircuitboard
id: APECircuitboard
diff --git a/Resources/Prototypes/Entities/Structures/Machines/anomaly_sync.yml b/Resources/Prototypes/Entities/Structures/Machines/anomaly_sync.yml
new file mode 100644
index 0000000000..d37cc714e2
--- /dev/null
+++ b/Resources/Prototypes/Entities/Structures/Machines/anomaly_sync.yml
@@ -0,0 +1,75 @@
+- type: entity
+ id: MachineAnomalySynchronizer
+ parent: [ BaseMachinePowered, ConstructibleMachine ]
+ name: anomaly synchronizer
+ description: A sophisticated device that reads changes in anomalous waves, and converts them into energy signals.
+ components:
+ - type: AnomalySynchronizer
+ - type: Machine
+ board: AnomalySynchronizerCircuitboard
+ - type: DeviceNetwork
+ deviceNetId: Wireless
+ - type: WirelessNetworkConnection
+ range: 300
+ - type: DeviceNetworkRequiresPower
+ - type: DeviceLinkSource
+ ports:
+ - Decaying
+ - Stabilize
+ - Growing
+ - Pulse
+ - Supercritical
+ - type: Sprite
+ noRot: true
+ sprite: Structures/Machines/anomaly_sync.rsi
+ layers:
+ - state: base
+ - state: energy
+ shader: unshaded
+ map: ["enum.PowerDeviceVisualLayers.Powered"]
+ - type: AmbientSound
+ enabled: false
+ sound:
+ path: /Audio/Machines/scan_loop.ogg
+ range: 5
+ volume: -8
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.35,-0.35,0.35,0.35"
+ density: 190
+ mask:
+ - MachineMask
+ layer:
+ - Impassable
+ - MidImpassable
+ - LowImpassable
+ hard: False
+ - type: Transform
+ anchored: true
+ noRot: false
+ - type: ApcPowerReceiver
+ powerLoad: 15000
+ needsPower: true
+ - type: UpgradePowerDraw
+ powerDrawMultiplier: 0.80
+ scaling: Exponential
+ - type: ItemPlacer
+ whitelist:
+ components:
+ - Anomaly
+ - type: DeviceList
+ - type: PointLight
+ radius: 1.8
+ energy: 1.6
+ color: "#b53ca1"
+ - type: LitOnPowered
+ - type: Appearance
+ - type: GenericVisualizer
+ visuals:
+ enum.PowerDeviceVisuals.Powered:
+ enum.PowerDeviceVisualLayers.Powered:
+ True: { visible: true }
+ False: { visible: false }
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index fb77167b73..b82f3f6828 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -366,6 +366,7 @@
- AnalysisComputerCircuitboard
- ExosuitFabricatorMachineCircuitboard
- AnomalyVesselCircuitboard
+ - AnomalySynchronizerCircuitboard
- APECircuitboard
- ArtifactAnalyzerMachineCircuitboard
- TraversalDistorterMachineCircuitboard
diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml
index bc54c78ca1..88b655644f 100644
--- a/Resources/Prototypes/Recipes/Lathes/electronics.yml
+++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml
@@ -248,6 +248,16 @@
Steel: 100
Glass: 900
+- type: latheRecipe
+ id: AnomalySynchronizerCircuitboard
+ result: AnomalySynchronizerCircuitboard
+ completetime: 4
+ materials:
+ Steel: 500
+ Glass: 700
+ Gold: 200
+ Silver: 100
+
- type: latheRecipe
id: APECircuitboard
result: APECircuitboard
diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml
index 02d66c06bf..363dee815e 100644
--- a/Resources/Prototypes/Research/experimental.yml
+++ b/Resources/Prototypes/Research/experimental.yml
@@ -99,16 +99,17 @@
- TraversalDistorterMachineCircuitboard
- type: technology
- id: MobileAnomalyTech
- name: research-technology-mobile-anomaly-tech
+ id: AdvancedAnomalyResearch
+ name: research-technology-advanced-anomaly-research
icon:
- sprite: Objects/Weapons/Guns/Revolvers/chimp.rsi
+ sprite: Structures/Machines/anomaly_sync.rsi
state: base
discipline: Experimental
tier: 2
cost: 10000
recipeUnlocks:
- WeaponPistolCHIMP
+ - AnomalySynchronizerCircuitboard
technologyPrerequisites:
- BasicAnomalousResearch
diff --git a/Resources/Textures/Structures/Machines/anomaly_sync.rsi/base.png b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/base.png
new file mode 100644
index 0000000000..e51f0e4a80
Binary files /dev/null and b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/base.png differ
diff --git a/Resources/Textures/Structures/Machines/anomaly_sync.rsi/energy.png b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/energy.png
new file mode 100644
index 0000000000..81e8758c05
Binary files /dev/null and b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/energy.png differ
diff --git a/Resources/Textures/Structures/Machines/anomaly_sync.rsi/meta.json b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/meta.json
new file mode 100644
index 0000000000..1a8f1a82ec
--- /dev/null
+++ b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/meta.json
@@ -0,0 +1,38 @@
+{
+ "version": 1,
+ "license": "CC0-1.0",
+ "copyright": "Created by ThrShuEd (github) for Space Station 14",
+ "size": {
+ "x": 48,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "base"
+ },
+ {
+ "name": "energy",
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pulse",
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Structures/Machines/anomaly_sync.rsi/pulse.png b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/pulse.png
new file mode 100644
index 0000000000..cceb35afcb
Binary files /dev/null and b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/pulse.png differ