Dynamic anomaly scanner texture (#37585)

This commit is contained in:
Quantum-cross
2025-09-04 15:11:03 -04:00
committed by GitHub
parent 12e8697648
commit 52c903cab8
25 changed files with 720 additions and 289 deletions

View File

@@ -0,0 +1,185 @@
using Content.Server.Anomaly.Components;
using Content.Server.Anomaly.Effects;
using Content.Shared.Anomaly;
using Content.Shared.Anomaly.Components;
using Content.Shared.DoAfter;
namespace Content.Server.Anomaly;
/// <inheritdoc cref="SharedAnomalyScannerSystem"/>
public sealed class AnomalyScannerSystem : SharedAnomalyScannerSystem
{
[Dependency] private readonly SecretDataAnomalySystem _secretData = default!;
[Dependency] private readonly AnomalySystem _anomaly = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AnomalySeverityChangedEvent>(OnScannerAnomalySeverityChanged);
SubscribeLocalEvent<AnomalyStabilityChangedEvent>(OnScannerAnomalyStabilityChanged);
SubscribeLocalEvent<AnomalyHealthChangedEvent>(OnScannerAnomalyHealthChanged);
SubscribeLocalEvent<AnomalyBehaviorChangedEvent>(OnScannerAnomalyBehaviorChanged);
Subs.BuiEvents<AnomalyScannerComponent>(
AnomalyScannerUiKey.Key,
subs => subs.Event<BoundUIOpenedEvent>(OnScannerUiOpened)
);
}
/// <summary> Updates device with passed anomaly data. </summary>
public void UpdateScannerWithNewAnomaly(EntityUid scanner, EntityUid anomaly, AnomalyScannerComponent? scannerComp = null, AnomalyComponent? anomalyComp = null)
{
if (!Resolve(scanner, ref scannerComp) || !Resolve(anomaly, ref anomalyComp))
return;
scannerComp.ScannedAnomaly = anomaly;
UpdateScannerUi(scanner, scannerComp);
TryComp<AppearanceComponent>(scanner, out var appearanceComp);
TryComp<SecretDataAnomalyComponent>(anomaly, out var secretDataComp);
Appearance.SetData(scanner, AnomalyScannerVisuals.HasAnomaly, true, appearanceComp);
var stability = _secretData.IsSecret(anomaly, AnomalySecretData.Stability, secretDataComp)
? AnomalyStabilityVisuals.Stable
: _anomaly.GetStabilityVisualOrStable((anomaly, anomalyComp));
Appearance.SetData(scanner, AnomalyScannerVisuals.AnomalyStability, stability, appearanceComp);
var severity = _secretData.IsSecret(anomaly, AnomalySecretData.Severity, secretDataComp)
? 0
: anomalyComp.Severity;
Appearance.SetData(scanner, AnomalyScannerVisuals.AnomalySeverity, severity, appearanceComp);
}
/// <summary> Update scanner interface. </summary>
public void UpdateScannerUi(EntityUid uid, AnomalyScannerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
TimeSpan? nextPulse = null;
if (TryComp<AnomalyComponent>(component.ScannedAnomaly, out var anomalyComponent))
nextPulse = anomalyComponent.NextPulseTime;
var state = new AnomalyScannerUserInterfaceState(_anomaly.GetScannerMessage(component), nextPulse);
UI.SetUiState(uid, AnomalyScannerUiKey.Key, state);
}
/// <inheritdoc />
public override void Update(float frameTime)
{
base.Update(frameTime);
var anomalyQuery = EntityQueryEnumerator<AnomalyComponent>();
while (anomalyQuery.MoveNext(out var ent, out var anomaly))
{
var secondsUntilNextPulse = (anomaly.NextPulseTime - Timing.CurTime).TotalSeconds;
UpdateScannerPulseTimers((ent, anomaly), secondsUntilNextPulse);
}
}
/// <inheritdoc />
protected override void OnDoAfter(EntityUid uid, AnomalyScannerComponent component, DoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Target == null)
return;
base.OnDoAfter(uid, component, args);
UpdateScannerWithNewAnomaly(uid, args.Args.Target.Value, component);
}
private void OnScannerAnomalyHealthChanged(ref AnomalyHealthChangedEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
}
}
private void OnScannerUiOpened(EntityUid uid, AnomalyScannerComponent component, BoundUIOpenedEvent args)
{
UpdateScannerUi(uid, component);
}
private void OnScannerAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
{
var severity = _secretData.IsSecret(args.Anomaly, AnomalySecretData.Severity) ? 0 : args.Severity;
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
Appearance.SetData(uid, AnomalyScannerVisuals.AnomalySeverity, severity);
}
}
private void OnScannerAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
{
var stability = _secretData.IsSecret(args.Anomaly, AnomalySecretData.Stability)
? AnomalyStabilityVisuals.Stable
: _anomaly.GetStabilityVisualOrStable(args.Anomaly);
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
Appearance.SetData(uid, AnomalyScannerVisuals.AnomalyStability, stability);
}
}
private void OnScannerAnomalyBehaviorChanged(ref AnomalyBehaviorChangedEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
// If a field becomes secret, we want to set it to 0 or stable
// If a field becomes visible, we need to set it to the correct value, so we need to get the AnomalyComponent
if (!TryComp<AnomalyComponent>(args.Anomaly, out var anomalyComp))
return;
TryComp<AppearanceComponent>(uid, out var appearanceComp);
TryComp<SecretDataAnomalyComponent>(args.Anomaly, out var secretDataComp);
var severity = _secretData.IsSecret(args.Anomaly, AnomalySecretData.Severity, secretDataComp)
? 0
: anomalyComp.Severity;
Appearance.SetData(uid, AnomalyScannerVisuals.AnomalySeverity, severity, appearanceComp);
var stability = _secretData.IsSecret(args.Anomaly, AnomalySecretData.Stability, secretDataComp)
? AnomalyStabilityVisuals.Stable
: _anomaly.GetStabilityVisualOrStable((args.Anomaly, anomalyComp));
Appearance.SetData(uid, AnomalyScannerVisuals.AnomalyStability, stability, appearanceComp);
}
}
private void UpdateScannerPulseTimers(Entity<AnomalyComponent> anomalyEnt, double secondsUntilNextPulse)
{
if (secondsUntilNextPulse > 5)
return;
var rounded = Math.Max(0, (int)Math.Ceiling(secondsUntilNextPulse));
var scannerQuery = EntityQueryEnumerator<AnomalyScannerComponent>();
while (scannerQuery.MoveNext(out var scannerUid, out var scanner))
{
if (scanner.ScannedAnomaly != anomalyEnt)
continue;
Appearance.SetData(scannerUid, AnomalyScannerVisuals.AnomalyNextPulse, rounded);
}
}
}

View File

@@ -1,241 +0,0 @@
using Content.Server.Anomaly.Components;
using Content.Shared.Anomaly;
using Content.Shared.Anomaly.Components;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.Anomaly;
/// <summary>
/// This handles the anomaly scanner and it's UI updates.
/// </summary>
public sealed partial class AnomalySystem
{
private void InitializeScanner()
{
SubscribeLocalEvent<AnomalyScannerComponent, BoundUIOpenedEvent>(OnScannerUiOpened);
SubscribeLocalEvent<AnomalyScannerComponent, AfterInteractEvent>(OnScannerAfterInteract);
SubscribeLocalEvent<AnomalyScannerComponent, ScannerDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<AnomalySeverityChangedEvent>(OnScannerAnomalySeverityChanged);
SubscribeLocalEvent<AnomalyHealthChangedEvent>(OnScannerAnomalyHealthChanged);
SubscribeLocalEvent<AnomalyBehaviorChangedEvent>(OnScannerAnomalyBehaviorChanged);
}
private void OnScannerAnomalyShutdown(ref AnomalyShutdownEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
_ui.CloseUi(uid, AnomalyScannerUiKey.Key);
}
}
private void OnScannerAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
}
}
private void OnScannerAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
}
}
private void OnScannerAnomalyHealthChanged(ref AnomalyHealthChangedEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
}
}
private void OnScannerAnomalyBehaviorChanged(ref AnomalyBehaviorChangedEvent args)
{
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(uid, component);
}
}
private void OnScannerUiOpened(EntityUid uid, AnomalyScannerComponent component, BoundUIOpenedEvent args)
{
UpdateScannerUi(uid, component);
}
private void OnScannerAfterInteract(EntityUid uid, AnomalyScannerComponent component, AfterInteractEvent args)
{
if (args.Target is not { } target)
return;
if (!HasComp<AnomalyComponent>(target))
return;
if (!args.CanReach)
return;
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.ScanDoAfterDuration, new ScannerDoAfterEvent(), uid, target: target, used: uid)
{
DistanceThreshold = 2f
});
}
private void OnDoAfter(EntityUid uid, AnomalyScannerComponent component, DoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Target == null)
return;
Audio.PlayPvs(component.CompleteSound, uid);
Popup.PopupEntity(Loc.GetString("anomaly-scanner-component-scan-complete"), uid);
UpdateScannerWithNewAnomaly(uid, args.Args.Target.Value, component);
_ui.OpenUi(uid, AnomalyScannerUiKey.Key, args.User);
args.Handled = true;
}
public void UpdateScannerUi(EntityUid uid, AnomalyScannerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
TimeSpan? nextPulse = null;
if (TryComp<AnomalyComponent>(component.ScannedAnomaly, out var anomalyComponent))
nextPulse = anomalyComponent.NextPulseTime;
var state = new AnomalyScannerUserInterfaceState(GetScannerMessage(component), nextPulse);
_ui.SetUiState(uid, AnomalyScannerUiKey.Key, state);
}
public void UpdateScannerWithNewAnomaly(EntityUid scanner, EntityUid anomaly, AnomalyScannerComponent? scannerComp = null, AnomalyComponent? anomalyComp = null)
{
if (!Resolve(scanner, ref scannerComp) || !Resolve(anomaly, ref anomalyComp))
return;
scannerComp.ScannedAnomaly = anomaly;
UpdateScannerUi(scanner, scannerComp);
}
public FormattedMessage GetScannerMessage(AnomalyScannerComponent component)
{
var msg = new FormattedMessage();
if (component.ScannedAnomaly is not { } anomaly || !TryComp<AnomalyComponent>(anomaly, out var anomalyComp))
{
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-no-anomaly"));
return msg;
}
TryComp<SecretDataAnomalyComponent>(anomaly, out var secret);
//Severity
if (secret != null && secret.Secret.Contains(AnomalySecretData.Severity))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P"))));
msg.PushNewline();
//Stability
if (secret != null && secret.Secret.Contains(AnomalySecretData.Stability))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-stability-unknown"));
else
{
string stateLoc;
if (anomalyComp.Stability < anomalyComp.DecayThreshold)
stateLoc = Loc.GetString("anomaly-scanner-stability-low");
else if (anomalyComp.Stability > anomalyComp.GrowthThreshold)
stateLoc = Loc.GetString("anomaly-scanner-stability-high");
else
stateLoc = Loc.GetString("anomaly-scanner-stability-medium");
msg.AddMarkupOrThrow(stateLoc);
}
msg.PushNewline();
//Point output
if (secret != null && secret.Secret.Contains(AnomalySecretData.OutputPoint))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp))));
msg.PushNewline();
msg.PushNewline();
//Particles title
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-readout"));
msg.PushNewline();
//Danger
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleDanger))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType))));
msg.PushNewline();
//Unstable
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleUnstable))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType))));
msg.PushNewline();
//Containment
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleContainment))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType))));
msg.PushNewline();
//Transformation
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleTransformation))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType))));
//Behavior
msg.PushNewline();
msg.PushNewline();
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-title"));
msg.PushNewline();
if (secret != null && secret.Secret.Contains(AnomalySecretData.Behavior))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-unknown"));
else
{
if (anomalyComp.CurrentBehavior != null)
{
var behavior = _prototype.Index(anomalyComp.CurrentBehavior.Value);
msg.AddMarkupOrThrow("- " + Loc.GetString(behavior.Description));
msg.PushNewline();
var mod = Math.Floor((behavior.EarnPointModifier) * 100);
msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod)));
}
else
{
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-balanced"));
}
}
//The timer at the end here is actually added in the ui itself.
return msg;
}
}

View File

@@ -22,20 +22,7 @@ public sealed partial class AnomalySystem
SubscribeLocalEvent<AnomalyVesselComponent, InteractUsingEvent>(OnVesselInteractUsing);
SubscribeLocalEvent<AnomalyVesselComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<AnomalyVesselComponent, ResearchServerGetPointsPerSecondEvent>(OnVesselGetPointsPerSecond);
SubscribeLocalEvent<AnomalyShutdownEvent>(OnShutdown);
SubscribeLocalEvent<AnomalyStabilityChangedEvent>(OnStabilityChanged);
}
private void OnStabilityChanged(ref AnomalyStabilityChangedEvent args)
{
OnVesselAnomalyStabilityChanged(ref args);
OnScannerAnomalyStabilityChanged(ref args);
}
private void OnShutdown(ref AnomalyShutdownEvent args)
{
OnVesselAnomalyShutdown(ref args);
OnScannerAnomalyShutdown(ref args);
SubscribeLocalEvent<AnomalyShutdownEvent>(OnVesselAnomalyShutdown);
}
private void OnExamined(EntityUid uid, AnomalyVesselComponent component, ExaminedEvent args)
@@ -141,21 +128,10 @@ public sealed partial class AnomalySystem
if (_pointLight.TryGetLight(uid, out var pointLightComponent))
_pointLight.SetEnabled(uid, on, pointLightComponent);
// arbitrary value for the generic visualizer to use.
// i didn't feel like making an enum for this.
var value = 1;
if (TryComp<AnomalyComponent>(component.Anomaly, out var anomalyComp))
{
if (anomalyComp.Stability <= anomalyComp.DecayThreshold)
{
value = 2;
}
else if (anomalyComp.Stability >= anomalyComp.GrowthThreshold)
{
value = 3;
}
}
Appearance.SetData(uid, AnomalyVesselVisuals.AnomalyState, value, appearanceComponent);
if (component.Anomaly == null || !TryGetStabilityVisual(component.Anomaly.Value, out var visual))
visual = AnomalyStabilityVisuals.Stable;
Appearance.SetData(uid, AnomalyVesselVisuals.AnomalySeverity, visual, appearanceComponent);
_ambient.SetAmbience(uid, on);
}

View File

@@ -9,7 +9,6 @@ using Content.Server.Station.Systems;
using Content.Shared.Anomaly;
using Content.Shared.Anomaly.Components;
using Content.Shared.Anomaly.Prototypes;
using Content.Shared.DoAfter;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Robust.Server.GameObjects;
@@ -18,6 +17,7 @@ using Robust.Shared.Configuration;
using Robust.Shared.Physics.Events;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Anomaly;
@@ -30,7 +30,6 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly AmbientSoundSystem _ambient = default!;
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly ExplosionSystem _explosion = default!;
[Dependency] private readonly MaterialStorageSystem _material = default!;
[Dependency] private readonly SharedPointLightSystem _pointLight = default!;
@@ -53,10 +52,9 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
SubscribeLocalEvent<AnomalyComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<AnomalyComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<AnomalyComponent, StartCollideEvent>(OnStartCollide);
SubscribeLocalEvent<AnomalyStabilityChangedEvent>(OnVesselAnomalyStabilityChanged);
InitializeGenerator();
InitializeScanner();
InitializeVessel();
InitializeCommands();
}
@@ -218,4 +216,112 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
EntityManager.RemoveComponents(anomaly, behavior.Components);
}
#endregion
#region Information
/// <summary>
/// Get a formatted message with a summary of all anomaly information for putting on a UI.
/// </summary>
public FormattedMessage GetScannerMessage(AnomalyScannerComponent component)
{
var msg = new FormattedMessage();
if (component.ScannedAnomaly is not { } anomaly || !TryComp<AnomalyComponent>(anomaly, out var anomalyComp))
{
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-no-anomaly"));
return msg;
}
TryComp<SecretDataAnomalyComponent>(anomaly, out var secret);
//Severity
if (secret != null && secret.Secret.Contains(AnomalySecretData.Severity))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P"))));
msg.PushNewline();
//Stability
if (secret != null && secret.Secret.Contains(AnomalySecretData.Stability))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-stability-unknown"));
else
{
string stateLoc;
if (anomalyComp.Stability < anomalyComp.DecayThreshold)
stateLoc = Loc.GetString("anomaly-scanner-stability-low");
else if (anomalyComp.Stability > anomalyComp.GrowthThreshold)
stateLoc = Loc.GetString("anomaly-scanner-stability-high");
else
stateLoc = Loc.GetString("anomaly-scanner-stability-medium");
msg.AddMarkupOrThrow(stateLoc);
}
msg.PushNewline();
//Point output
if (secret != null && secret.Secret.Contains(AnomalySecretData.OutputPoint))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp))));
msg.PushNewline();
msg.PushNewline();
//Particles title
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-readout"));
msg.PushNewline();
//Danger
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleDanger))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType))));
msg.PushNewline();
//Unstable
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleUnstable))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType))));
msg.PushNewline();
//Containment
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleContainment))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType))));
msg.PushNewline();
//Transformation
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleTransformation))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation-unknown"));
else
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType))));
//Behavior
msg.PushNewline();
msg.PushNewline();
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-title"));
msg.PushNewline();
if (secret != null && secret.Secret.Contains(AnomalySecretData.Behavior))
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-unknown"));
else
{
if (anomalyComp.CurrentBehavior != null)
{
var behavior = _prototype.Index(anomalyComp.CurrentBehavior.Value);
msg.AddMarkupOrThrow("- " + Loc.GetString(behavior.Description));
msg.PushNewline();
var mod = Math.Floor((behavior.EarnPointModifier) * 100);
msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod)));
}
else
{
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-balanced"));
}
}
//The timer at the end here is actually added in the ui itself.
return msg;
}
#endregion
}

View File

@@ -1,30 +0,0 @@
using Content.Shared.Anomaly;
using Robust.Shared.Audio;
namespace Content.Server.Anomaly.Components;
/// <summary>
/// This is used for scanning anomalies and
/// displaying information about them in the ui
/// </summary>
[RegisterComponent, Access(typeof(SharedAnomalySystem))]
public sealed partial class AnomalyScannerComponent : Component
{
/// <summary>
/// The anomaly that was last scanned by this scanner.
/// </summary>
[ViewVariables]
public EntityUid? ScannedAnomaly;
/// <summary>
/// How long the scan takes
/// </summary>
[DataField("scanDoAfterDuration")]
public float ScanDoAfterDuration = 5;
/// <summary>
/// The sound plays when the scan finished
/// </summary>
[DataField("completeSound")]
public SoundSpecifier? CompleteSound = new SoundPathSpecifier("/Audio/Items/beep.ogg");
}

View File

@@ -36,5 +36,13 @@ public sealed class SecretDataAnomalySystem : EntitySystem
component.Secret.Add(_random.PickAndTake(_deita));
}
}
public bool IsSecret(EntityUid uid, AnomalySecretData item, SecretDataAnomalyComponent? component = null)
{
if (!Resolve(uid, ref component, logMissing: false))
return false;
return component.Secret.Contains(item);
}
}

View File

@@ -20,6 +20,7 @@ namespace Content.Server.Entry
"LightFade",
"HolidayRsiSwap",
"OptionsVisualizer",
"AnomalyScannerScreen",
"MultipartMachineGhost"
};
}