Predict anomaly synchronizer (#39321)
* predict anomaly synchronizer * pvs * lambda * Update Resources/Locale/en-US/anomaly/anomaly.ftl --------- Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
This commit is contained in:
@@ -1,33 +1,30 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
|
||||||
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.Anomaly.Components;
|
||||||
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Content.Shared.Power.EntitySystems;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.Anomaly;
|
namespace Content.Shared.Anomaly;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// a device that allows you to translate anomaly activity into multitool signals.
|
/// A device that allows you to translate anomaly activity into multitool signals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
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 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!;
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly SharedAnomalySystem _anomaly = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly SharedPowerReceiverSystem _power = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -47,27 +44,41 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var curTime = _timing.CurTime;
|
||||||
var query = EntityQueryEnumerator<AnomalySynchronizerComponent, TransformComponent>();
|
var query = EntityQueryEnumerator<AnomalySynchronizerComponent, TransformComponent>();
|
||||||
while (query.MoveNext(out var uid, out var sync, out var xform))
|
while (query.MoveNext(out var uid, out var sync, out var synchronizerTransform))
|
||||||
{
|
{
|
||||||
if (sync.ConnectedAnomaly is null)
|
if (sync.ConnectedAnomaly == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (_timing.CurTime < sync.NextCheckTime)
|
if (curTime < sync.NextCheckTime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sync.NextCheckTime += sync.CheckFrequency;
|
sync.NextCheckTime += sync.CheckFrequency;
|
||||||
|
Dirty(uid, sync);
|
||||||
|
|
||||||
if (Transform(sync.ConnectedAnomaly.Value).MapUid != Transform(uid).MapUid)
|
if (TerminatingOrDeleted(sync.ConnectedAnomaly))
|
||||||
{
|
{
|
||||||
DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value);
|
DisconnectFromAnomaly((uid, sync));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!xform.Coordinates.TryDistance(EntityManager, Transform(sync.ConnectedAnomaly.Value).Coordinates, out var distance))
|
// Use TryComp instead of Transform(uid) to take care of cases where the anomaly is out of
|
||||||
|
// PVS range on the client, but the synchronizer isn't.
|
||||||
|
if (!TryComp(sync.ConnectedAnomaly.Value, out TransformComponent? anomalyTransform))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (anomalyTransform.MapUid != synchronizerTransform.MapUid)
|
||||||
|
{
|
||||||
|
DisconnectFromAnomaly((uid, sync));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!synchronizerTransform.Coordinates.TryDistance(EntityManager, anomalyTransform.Coordinates, out var distance))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (distance > sync.AttachRange)
|
if (distance > sync.AttachRange)
|
||||||
DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value);
|
DisconnectFromAnomaly((uid, sync));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,11 +87,9 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryAttachNearbyAnomaly(Entity<AnomalySynchronizerComponent> ent, EntityUid? user = null)
|
public bool TryAttachNearbyAnomaly(Entity<AnomalySynchronizerComponent> ent, EntityUid? user = null)
|
||||||
{
|
{
|
||||||
if (!_power.IsPowered(ent))
|
if (!_power.IsPowered(ent.Owner))
|
||||||
{
|
{
|
||||||
if (user is not null)
|
_popup.PopupClient(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent)), ent, user);
|
||||||
_popup.PopupEntity(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent)), ent, user.Value);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,13 +98,11 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
|
|
||||||
if (anomaly.Owner is { Valid: false }) // no anomaly in range
|
if (anomaly.Owner is { Valid: false }) // no anomaly in range
|
||||||
{
|
{
|
||||||
if (user is not null)
|
_popup.PopupClient(Loc.GetString("anomaly-sync-no-anomaly"), ent, user);
|
||||||
_popup.PopupEntity(Loc.GetString("anomaly-sync-no-anomaly"), ent, user.Value);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectToAnomaly(ent, anomaly);
|
ConnectToAnomaly(ent, anomaly, user);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,10 +111,10 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
if (args.Powered)
|
if (args.Powered)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ent.Comp.ConnectedAnomaly is null)
|
if (ent.Comp.ConnectedAnomaly == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DisconnectFromAnomaly(ent, ent.Comp.ConnectedAnomaly.Value);
|
DisconnectFromAnomaly(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExamined(Entity<AnomalySynchronizerComponent> ent, ref ExaminedEvent args)
|
private void OnExamined(Entity<AnomalySynchronizerComponent> ent, ref ExaminedEvent args)
|
||||||
@@ -117,32 +124,43 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnGetInteractionVerbs(Entity<AnomalySynchronizerComponent> ent, ref GetVerbsEvent<InteractionVerb> args)
|
private void OnGetInteractionVerbs(Entity<AnomalySynchronizerComponent> ent, ref GetVerbsEvent<InteractionVerb> args)
|
||||||
{
|
{
|
||||||
if (!args.CanAccess || !args.CanInteract || args.Hands is null || ent.Comp.ConnectedAnomaly.HasValue)
|
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var user = args.User;
|
var user = args.User;
|
||||||
|
|
||||||
|
if (ent.Comp.ConnectedAnomaly == null)
|
||||||
|
{
|
||||||
args.Verbs.Add(new()
|
args.Verbs.Add(new()
|
||||||
{
|
{
|
||||||
Act = () =>
|
Act = () => TryAttachNearbyAnomaly(ent, user),
|
||||||
{
|
|
||||||
TryAttachNearbyAnomaly(ent, user);
|
|
||||||
},
|
|
||||||
Message = Loc.GetString("anomaly-sync-connect-verb-message", ("machine", ent)),
|
Message = Loc.GetString("anomaly-sync-connect-verb-message", ("machine", ent)),
|
||||||
Text = Loc.GetString("anomaly-sync-connect-verb-text"),
|
Text = Loc.GetString("anomaly-sync-connect-verb-text"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.Verbs.Add(new()
|
||||||
|
{
|
||||||
|
Act = () => DisconnectFromAnomaly(ent, user),
|
||||||
|
Message = Loc.GetString("anomaly-sync-disconnect-verb-message", ("machine", ent)),
|
||||||
|
Text = Loc.GetString("anomaly-sync-disconnect-verb-text"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnInteractHand(Entity<AnomalySynchronizerComponent> ent, ref InteractHandEvent args)
|
private void OnInteractHand(Entity<AnomalySynchronizerComponent> ent, ref InteractHandEvent args)
|
||||||
{
|
{
|
||||||
TryAttachNearbyAnomaly(ent, args.User);
|
TryAttachNearbyAnomaly(ent, args.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConnectToAnomaly(Entity<AnomalySynchronizerComponent> ent, Entity<AnomalyComponent> anomaly)
|
private void ConnectToAnomaly(Entity<AnomalySynchronizerComponent> ent, Entity<AnomalyComponent> anomaly, EntityUid? user = null)
|
||||||
{
|
{
|
||||||
if (ent.Comp.ConnectedAnomaly == anomaly)
|
if (ent.Comp.ConnectedAnomaly == anomaly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ent.Comp.ConnectedAnomaly = anomaly;
|
ent.Comp.ConnectedAnomaly = anomaly;
|
||||||
|
Dirty(ent);
|
||||||
//move the anomaly to the center of the synchronizer, for aesthetics.
|
//move the anomaly to the center of the synchronizer, for aesthetics.
|
||||||
var targetXform = _transform.GetWorldPosition(ent);
|
var targetXform = _transform.GetWorldPosition(ent);
|
||||||
_transform.SetWorldPosition(anomaly, targetXform);
|
_transform.SetWorldPosition(anomaly, targetXform);
|
||||||
@@ -150,27 +168,27 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
if (ent.Comp.PulseOnConnect)
|
if (ent.Comp.PulseOnConnect)
|
||||||
_anomaly.DoAnomalyPulse(anomaly, anomaly);
|
_anomaly.DoAnomalyPulse(anomaly, anomaly);
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("anomaly-sync-connected"), ent, PopupType.Medium);
|
_popup.PopupPredicted(Loc.GetString("anomaly-sync-connected"), ent, user, PopupType.Medium);
|
||||||
_audio.PlayPvs(ent.Comp.ConnectedSound, ent);
|
_audio.PlayPredicted(ent.Comp.ConnectedSound, ent, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
|
//TODO: 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.
|
//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 DisconnectFromAnomaly(Entity<AnomalySynchronizerComponent> ent, EntityUid other)
|
private void DisconnectFromAnomaly(Entity<AnomalySynchronizerComponent> ent, EntityUid? user = null)
|
||||||
{
|
{
|
||||||
if (ent.Comp.ConnectedAnomaly == null)
|
if (ent.Comp.ConnectedAnomaly == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TryComp<AnomalyComponent>(other, out var anomaly))
|
if (ent.Comp.PulseOnDisconnect && TryComp<AnomalyComponent>(ent.Comp.ConnectedAnomaly, out var anomaly))
|
||||||
{
|
{
|
||||||
if (ent.Comp.PulseOnDisconnect)
|
|
||||||
_anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly);
|
_anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly);
|
||||||
}
|
}
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("anomaly-sync-disconnected"), ent, PopupType.Large);
|
_popup.PopupPredicted(Loc.GetString("anomaly-sync-disconnected"), ent, user, PopupType.Large);
|
||||||
_audio.PlayPvs(ent.Comp.ConnectedSound, ent);
|
_audio.PlayPredicted(ent.Comp.DisconnectedSound, ent, user);
|
||||||
|
|
||||||
ent.Comp.ConnectedAnomaly = null;
|
ent.Comp.ConnectedAnomaly = null;
|
||||||
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAnomalyPulse(ref AnomalyPulseEvent args)
|
private void OnAnomalyPulse(ref AnomalyPulseEvent args)
|
||||||
@@ -184,19 +202,19 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
if (!_power.IsPowered(uid))
|
if (!_power.IsPowered(uid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_signal.InvokePort(uid, component.PulsePort);
|
_deviceLink.InvokePort(uid, component.PulsePort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
|
private void OnAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
|
||||||
{
|
{
|
||||||
var query = EntityQueryEnumerator<AnomalySynchronizerComponent>();
|
var query = EntityQueryEnumerator<AnomalySynchronizerComponent>();
|
||||||
while (query.MoveNext(out var ent, out var component))
|
while (query.MoveNext(out var uid, out var component))
|
||||||
{
|
{
|
||||||
if (args.Anomaly != component.ConnectedAnomaly)
|
if (args.Anomaly != component.ConnectedAnomaly)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_power.IsPowered(ent))
|
if (!_power.IsPowered(uid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//The superscritical port is invoked not at the AnomalySupercriticalEvent,
|
//The superscritical port is invoked not at the AnomalySupercriticalEvent,
|
||||||
@@ -204,34 +222,34 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
|||||||
//ATTENTION! the console command supercriticalanomaly does not work here,
|
//ATTENTION! the console command supercriticalanomaly does not work here,
|
||||||
//as it forcefully causes growth to start without increasing severity.
|
//as it forcefully causes growth to start without increasing severity.
|
||||||
if (args.Severity >= 1)
|
if (args.Severity >= 1)
|
||||||
_signal.InvokePort(ent, component.SupercritPort);
|
_deviceLink.InvokePort(uid, component.SupercritPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
|
private void OnAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
|
||||||
{
|
{
|
||||||
Entity<AnomalyComponent> anomaly = (args.Anomaly, Comp<AnomalyComponent>(args.Anomaly));
|
var anomaly = Comp<AnomalyComponent>(args.Anomaly);
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<AnomalySynchronizerComponent>();
|
var query = EntityQueryEnumerator<AnomalySynchronizerComponent>();
|
||||||
while (query.MoveNext(out var ent, out var component))
|
while (query.MoveNext(out var uid, out var sync))
|
||||||
{
|
{
|
||||||
if (component.ConnectedAnomaly != anomaly)
|
if (sync.ConnectedAnomaly != args.Anomaly)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_power.IsPowered(ent))
|
if (!_power.IsPowered(uid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (args.Stability < anomaly.Comp.DecayThreshold)
|
if (args.Stability < anomaly.DecayThreshold)
|
||||||
{
|
{
|
||||||
_signal.InvokePort(ent, component.DecayingPort);
|
_deviceLink.InvokePort(uid, sync.DecayingPort);
|
||||||
}
|
}
|
||||||
else if (args.Stability > anomaly.Comp.GrowthThreshold)
|
else if (args.Stability > anomaly.GrowthThreshold)
|
||||||
{
|
{
|
||||||
_signal.InvokePort(ent, component.GrowingPort);
|
_deviceLink.InvokePort(uid, sync.GrowingPort);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_signal.InvokePort(ent, component.StabilizePort);
|
_deviceLink.InvokePort(uid, sync.StabilizePort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,46 +1,51 @@
|
|||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
namespace Content.Server.Anomaly.Components;
|
namespace Content.Shared.Anomaly.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// a device that allows you to translate anomaly activity into multitool signals.
|
/// A device that allows you to translate anomaly activity into multitool signals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, AutoGenerateComponentPause, Access(typeof(AnomalySynchronizerSystem))]
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||||
|
[Access(typeof(AnomalySynchronizerSystem))]
|
||||||
public sealed partial class AnomalySynchronizerComponent : Component
|
public sealed partial class AnomalySynchronizerComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The uid of the anomaly to which the synchronizer is connected.
|
/// The uid of the anomaly to which the synchronizer is connected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, AutoNetworkedField]
|
||||||
public EntityUid? ConnectedAnomaly;
|
public EntityUid? ConnectedAnomaly;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should the anomaly pulse when connected to the synchronizer?
|
/// Should the anomaly pulse when connected to the synchronizer?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField]
|
||||||
public bool PulseOnConnect = true;
|
public bool PulseOnConnect = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should the anomaly pulse when disconnected from synchronizer?
|
/// Should the anomaly pulse when disconnected from synchronizer?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField]
|
||||||
public bool PulseOnDisconnect = false;
|
public bool PulseOnDisconnect = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// minimum distance from the synchronizer to the anomaly to be attached
|
/// Minimum distance from the synchronizer to the anomaly to be attached.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField]
|
||||||
public float AttachRange = 0.4f;
|
public float AttachRange = 0.4f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Periodicheski checks to see if the anomaly has moved to disconnect it.
|
/// Periodically checks to see if the anomaly has moved to disconnect it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField]
|
||||||
public TimeSpan CheckFrequency = TimeSpan.FromSeconds(1f);
|
public TimeSpan CheckFrequency = TimeSpan.FromSeconds(1f);
|
||||||
|
|
||||||
[DataField, AutoPausedField]
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||||
|
[AutoNetworkedField, AutoPausedField]
|
||||||
public TimeSpan NextCheckTime = TimeSpan.Zero;
|
public TimeSpan NextCheckTime = TimeSpan.Zero;
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
@@ -58,9 +63,9 @@ public sealed partial class AnomalySynchronizerComponent : Component
|
|||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<SourcePortPrototype> SupercritPort = "Supercritical";
|
public ProtoId<SourcePortPrototype> SupercritPort = "Supercritical";
|
||||||
|
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField]
|
||||||
public SoundSpecifier ConnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg");
|
public SoundSpecifier ConnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg");
|
||||||
|
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField]
|
||||||
public SoundSpecifier DisconnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg");
|
public SoundSpecifier DisconnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg");
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,8 @@ anomaly-sync-examine-connected = It is [color=darkgreen]attached[/color] to an a
|
|||||||
anomaly-sync-examine-not-connected = It is [color=darkred]not attached[/color] to an anomaly.
|
anomaly-sync-examine-not-connected = It is [color=darkred]not attached[/color] to an anomaly.
|
||||||
anomaly-sync-connect-verb-text = Attach anomaly
|
anomaly-sync-connect-verb-text = Attach anomaly
|
||||||
anomaly-sync-connect-verb-message = Attach a nearby anomaly to {THE($machine)}.
|
anomaly-sync-connect-verb-message = Attach a nearby anomaly to {THE($machine)}.
|
||||||
|
anomaly-sync-disconnect-verb-text = Detach anomaly
|
||||||
|
anomaly-sync-disconnect-verb-message = Detach the connected anomaly from {THE($machine)}.
|
||||||
|
|
||||||
anomaly-generator-ui-title = Anomaly Generator
|
anomaly-generator-ui-title = Anomaly Generator
|
||||||
anomaly-generator-fuel-display = Fuel:
|
anomaly-generator-fuel-display = Fuel:
|
||||||
|
|||||||
Reference in New Issue
Block a user