]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Anomaly Synchronizer (#20945)
authorEd <96445749+TheShuEd@users.noreply.github.com>
Mon, 6 Nov 2023 04:02:02 +0000 (07:02 +0300)
committerGitHub <noreply@github.com>
Mon, 6 Nov 2023 04:02:02 +0000 (21:02 -0700)
* added textures and basic prototype without functionality

* add full functional

* finish work

* fix naming

* reduce random anomaly spawner offset

* Update AnomalySystem.Vessel.cs

* Update SharedAnomalySystem.cs

* Update SharedAnomalySystem.cs

* Update production.yml

* fix errors

* fix?

* Update anomaly_sync.yml

* deltanedas code fixes. Thx, deltanedas!

* git what

* fix yml

* fix yml 2

* meh, try again

* work, work, work

* fix powered checking. now component work also without ApcPowerReceiving

* now supercrit port invoke on start growing, not after explosion
fix errors

* deltanedas fix pack 1

* Update AnomalySynchronizerComponent.cs

20 files changed:
Content.Server/Anomaly/AnomalySynchronizerSystem.cs [new file with mode: 0644]
Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs [new file with mode: 0644]
Content.Shared/Anomaly/Components/AnomalyComponent.cs
Content.Shared/Anomaly/SharedAnomalySystem.cs
Resources/Audio/Machines/anomaly_sync_connect.ogg [new file with mode: 0644]
Resources/Audio/Machines/attributions.yml
Resources/Locale/en-US/anomaly/anomaly.ftl
Resources/Locale/en-US/machine-linking/transmitter_ports.ftl
Resources/Locale/en-US/research/technologies.ftl
Resources/Prototypes/DeviceLinking/source_ports.yml
Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml
Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
Resources/Prototypes/Entities/Structures/Machines/anomaly_sync.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Machines/lathe.yml
Resources/Prototypes/Recipes/Lathes/electronics.yml
Resources/Prototypes/Research/experimental.yml
Resources/Textures/Structures/Machines/anomaly_sync.rsi/base.png [new file with mode: 0644]
Resources/Textures/Structures/Machines/anomaly_sync.rsi/energy.png [new file with mode: 0644]
Resources/Textures/Structures/Machines/anomaly_sync.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Machines/anomaly_sync.rsi/pulse.png [new file with mode: 0644]

diff --git a/Content.Server/Anomaly/AnomalySynchronizerSystem.cs b/Content.Server/Anomaly/AnomalySynchronizerSystem.cs
new file mode 100644 (file)
index 0000000..6e881aa
--- /dev/null
@@ -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;
+
+/// <summary>
+/// a device that allows you to translate anomaly activity into multitool signals.
+/// </summary>
+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<AnomalySynchronizerComponent, InteractHandEvent>(OnInteractHand);
+        SubscribeLocalEvent<AnomalySynchronizerComponent, PowerChangedEvent>(OnPowerChanged);
+
+        SubscribeLocalEvent<AnomalyPulseEvent>(OnAnomalyPulse);
+        SubscribeLocalEvent<AnomalySeverityChangedEvent>(OnAnomalySeverityChanged);
+        SubscribeLocalEvent<AnomalyStabilityChangedEvent>(OnAnomalyStabilityChanged);
+    }
+
+    private void OnPowerChanged(EntityUid uid, AnomalySynchronizerComponent component, ref PowerChangedEvent args)
+    {
+        if (args.Powered)
+            return;
+
+        if (!TryComp<AnomalyComponent>(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<AnomalyComponent>(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<AnomalySynchronizerComponent>();
+        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<AnomalySynchronizerComponent>();
+        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<AnomalySynchronizerComponent>();
+        while (query.MoveNext(out var ent, out var component))
+        {
+            if (args.Anomaly != component.ConnectedAnomaly)
+                continue;
+            if (TryComp<ApcPowerReceiverComponent>(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 (file)
index 0000000..295ce88
--- /dev/null
@@ -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;
+
+/// <summary>
+/// a device that allows you to translate anomaly activity into multitool signals.
+/// </summary>
+[RegisterComponent, Access(typeof(AnomalySynchronizerSystem))]
+public sealed partial class AnomalySynchronizerComponent : Component
+{
+    /// <summary>
+    /// The uid of the anomaly to which the synchronizer is connected.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public EntityUid? ConnectedAnomaly;
+
+
+    [DataField]
+    public ProtoId<SourcePortPrototype> DecayingPort = "Decaying";
+
+    [DataField]
+    public ProtoId<SourcePortPrototype> StabilizePort = "Stabilize";
+
+    [DataField]
+    public ProtoId<SourcePortPrototype> GrowingPort = "Growing";
+
+    [DataField]
+    public ProtoId<SourcePortPrototype> PulsePort = "Pulse";
+
+    [DataField]
+    public ProtoId<SourcePortPrototype> 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");
+}
index cf3ba75aaaa794b3f540dabd8b13243d2a87079d..a6f4f6c0867d03a4b4bfb4106bc901f52e813c8f 100644 (file)
@@ -243,16 +243,17 @@ public sealed partial class AnomalyComponent : Component
 /// <summary>
 /// Event raised at regular intervals on an anomaly to do whatever its effect is.
 /// </summary>
+/// <param name="Anomaly">The anomaly pulsing</param>
 /// <param name="Stability"></param>
 /// <param name="Severity"></param>
 [ByRefEvent]
-public readonly record struct AnomalyPulseEvent(float Stability, float Severity);
+public readonly record struct AnomalyPulseEvent(EntityUid Anomaly, float Stability, float Severity);
 
 /// <summary>
 /// Event raised on an anomaly when it reaches a supercritical point.
 /// </summary>
 [ByRefEvent]
-public readonly record struct AnomalySupercriticalEvent;
+public readonly record struct AnomalySupercriticalEvent(EntityUid Anomaly);
 
 /// <summary>
 /// Event broadcast after an anomaly goes supercritical
index ca77544a15682f8180dfac61c85c37809feb8370..48413ac0018931693ae7fe69142aca4636b4959e 100644 (file)
@@ -109,9 +109,9 @@ public abstract class SharedAnomalySystem : EntitySystem
         var pulse = EnsureComp<AnomalyPulsingComponent>(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);
     }
 
     /// <summary>
@@ -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 (file)
index 0000000..c718eaf
Binary files /dev/null and b/Resources/Audio/Machines/anomaly_sync_connect.ogg differ
index bbf4ea9ac09f254ebf7fafc106185e86f47ffe63..3fa3aa06d7a84df47f2ed94bf33a9383748fd857 100644 (file)
@@ -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
index 29d51696944d9a5e397d9317ce87b257b1071fa0..83b992ce2356be50efb10250ef2dcc0aae578660 100644 (file)
@@ -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]
index 154f20eee7c337880d77cd16c98792ae49d82396..e5f92c5b0015197a53468c93cbb971dab83141df 100644 (file)
@@ -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
index 28c7377082afb37268262db9992bc0293329cc26..0f8a657aa43ec51eca0fb52d5ac57548b5668c32 100644 (file)
@@ -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
 
index 73e96978a7356f834546334ea9a68a39e08985db..6e97c3c809c62f89f5d6e6e677b8caf98cf3c3bf 100644 (file)
   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
index 043bf707b4db8a7e3de6176eebd4dfecb870767a..3b5d33ee06daad0135405684f34b0d46fab3f78d 100644 (file)
@@ -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.
index a25e5b7069d5a0b62d6f4b48abf36cf07f1ce7b5..2aed92bc28e8aafefaff26cb741e966a725f6410 100644 (file)
         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 (file)
index 0000000..d37cc71
--- /dev/null
@@ -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 }
index fb77167b733cf1760e03ed1f93871c2af3cefc87..b82f3f68285bf27fc689a5297a048f3057237d2a 100644 (file)
       - AnalysisComputerCircuitboard
       - ExosuitFabricatorMachineCircuitboard
       - AnomalyVesselCircuitboard
+      - AnomalySynchronizerCircuitboard
       - APECircuitboard
       - ArtifactAnalyzerMachineCircuitboard
       - TraversalDistorterMachineCircuitboard
index bc54c78ca1e38a6614a66834e2a0225c504503e9..88b655644feabede5af84265242ef2302749218b 100644 (file)
      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
index 02d66c06bf7d45e09ad5481d4e9723b9b87f46df..363dee815e3f395bb7e25f08644c0cbbc2715649 100644 (file)
   - 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 (file)
index 0000000..e51f0e4
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 (file)
index 0000000..81e8758
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 (file)
index 0000000..1a8f1a8
--- /dev/null
@@ -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 (file)
index 0000000..cceb35a
Binary files /dev/null and b/Resources/Textures/Structures/Machines/anomaly_sync.rsi/pulse.png differ