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:
148
Content.Server/Anomaly/AnomalySynchronizerSystem.cs
Normal file
148
Content.Server/Anomaly/AnomalySynchronizerSystem.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -110,8 +110,8 @@ public abstract class SharedAnomalySystem : EntitySystem
|
||||
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);
|
||||
}
|
||||
|
||||
BIN
Resources/Audio/Machines/anomaly_sync_connect.ogg
Normal file
BIN
Resources/Audio/Machines/anomaly_sync_connect.ogg
Normal file
Binary file not shown.
@@ -47,3 +47,8 @@
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from TG station."
|
||||
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/"
|
||||
@@ -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]
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
@@ -366,6 +366,7 @@
|
||||
- AnalysisComputerCircuitboard
|
||||
- ExosuitFabricatorMachineCircuitboard
|
||||
- AnomalyVesselCircuitboard
|
||||
- AnomalySynchronizerCircuitboard
|
||||
- APECircuitboard
|
||||
- ArtifactAnalyzerMachineCircuitboard
|
||||
- TraversalDistorterMachineCircuitboard
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
BIN
Resources/Textures/Structures/Machines/anomaly_sync.rsi/base.png
Normal file
BIN
Resources/Textures/Structures/Machines/anomaly_sync.rsi/base.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 923 B |
Binary file not shown.
|
After Width: | Height: | Size: 486 B |
@@ -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 |
Reference in New Issue
Block a user