Anomaly Synchronizer (#20945)

* 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
This commit is contained in:
Ed
2023-11-06 07:02:02 +03:00
committed by GitHub
parent ad1a280494
commit 8b3adf6085
20 changed files with 393 additions and 12 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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");
}

View 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

View 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);
}

Binary file not shown.

View 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"
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/"

View 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]

View 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.

View 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

View File

@@ -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

View 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.

View File

@@ -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

View File

@@ -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 }

View File

@@ -366,6 +366,7 @@
- AnalysisComputerCircuitboard
- ExosuitFabricatorMachineCircuitboard
- AnomalyVesselCircuitboard
- AnomalySynchronizerCircuitboard
- APECircuitboard
- ArtifactAnalyzerMachineCircuitboard
- TraversalDistorterMachineCircuitboard

View File

@@ -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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

View File

@@ -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
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B