diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs index 53c148d347..de3efbc485 100644 --- a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs @@ -31,6 +31,10 @@ public sealed class AnalysisConsoleBoundUserInterface : BoundUserInterface { SendMessage(new AnalysisConsoleScanButtonPressedMessage()); }; + _consoleMenu.OnPrintButtonPressed += _ => + { + SendMessage(new AnalysisConsolePrintButtonPressedMessage()); + }; _consoleMenu.OnDestroyButtonPressed += _ => { SendMessage(new AnalysisConsoleDestroyButtonPressedMessage()); @@ -44,8 +48,7 @@ public sealed class AnalysisConsoleBoundUserInterface : BoundUserInterface switch (state) { case AnalysisConsoleScanUpdateState msg: - _consoleMenu?.SetDestroyButtonDisabled(msg); - _consoleMenu?.SetScanButtonDisabled(msg); + _consoleMenu?.SetButtonsDisabled(msg); _consoleMenu?.UpdateInformationDisplay(msg); _consoleMenu?.UpdateProgressBar(msg); break; @@ -58,6 +61,7 @@ public sealed class AnalysisConsoleBoundUserInterface : BoundUserInterface if (!disposing) return; + _consoleMenu?.AnalysisDestroyWindow?.Close(); _consoleMenu?.Dispose(); } } diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml index fc705306aa..86060b29fe 100644 --- a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml @@ -15,6 +15,11 @@ Text="{Loc 'analysis-console-scan-button'}" ToolTip="{Loc 'analysis-console-scan-tooltip-info'}"> + + + + + + + diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisDestroyWindow.xaml.cs b/Content.Client/Xenoarchaeology/Ui/AnalysisDestroyWindow.xaml.cs new file mode 100644 index 0000000000..0c8a60460e --- /dev/null +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisDestroyWindow.xaml.cs @@ -0,0 +1,26 @@ +using Content.Client.Stylesheets; +using Content.Client.UserInterface.Controls; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Xenoarchaeology.Ui; + +[GenerateTypedNameReferences] +public sealed partial class AnalysisDestroyWindow : FancyWindow +{ + public event Action? OnYesButton; + + public AnalysisDestroyWindow() + { + RobustXamlLoader.Load(this); + + YesButton.AddStyleClass(StyleBase.ButtonCaution); + YesButton.OnPressed += a => + { + OnYesButton?.Invoke(a); + Close(); + }; + NoButton.OnPressed += _ => Close(); + } +} diff --git a/Content.Server/Xenoarchaeology/Equipment/Components/AnalysisConsoleComponent.cs b/Content.Server/Xenoarchaeology/Equipment/Components/AnalysisConsoleComponent.cs index 13e3b615ab..5a4b0e876a 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Components/AnalysisConsoleComponent.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Components/AnalysisConsoleComponent.cs @@ -1,6 +1,8 @@ using Content.Shared.MachineLinking; using Robust.Shared.Audio; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Utility; namespace Content.Server.Xenoarchaeology.Equipment.Components; @@ -28,4 +30,10 @@ public sealed class AnalysisConsoleComponent : Component /// [DataField("destroySound")] public SoundSpecifier DestroySound = new SoundPathSpecifier("/Audio/Effects/radpulse11.ogg"); + + /// + /// The entity spawned by a report. + /// + [DataField("reportEntityId", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ReportEntityId = "Paper"; } diff --git a/Content.Server/Xenoarchaeology/Equipment/Components/ArtifactAnalyzerComponent.cs b/Content.Server/Xenoarchaeology/Equipment/Components/ArtifactAnalyzerComponent.cs index 19d56c0482..4fc1604363 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Components/ArtifactAnalyzerComponent.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Components/ArtifactAnalyzerComponent.cs @@ -51,6 +51,9 @@ public sealed class ArtifactAnalyzerComponent : Component [ViewVariables] public HashSet Contacts = new(); + [ViewVariables(VVAccess.ReadWrite)] + public bool ReadyToPrint = false; + [DataField("scanFinishedSound")] public readonly SoundSpecifier ScanFinishedSound = new SoundPathSpecifier("/Audio/Machines/scan_finish.ogg"); diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs index af9092277c..f12c4272f0 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Server.Construction; using Content.Server.MachineLinking.Events; +using Content.Server.Paper; using Content.Server.Power.Components; using Content.Server.Research; using Content.Server.Research.Components; @@ -35,6 +36,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly ArtifactSystem _artifact = default!; + [Dependency] private readonly PaperSystem _paper = default!; /// public override void Initialize() @@ -56,6 +58,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem SubscribeLocalEvent(OnServerSelectionMessage); SubscribeLocalEvent(OnScanButton); + SubscribeLocalEvent(OnPrintButton); SubscribeLocalEvent(OnDestroyButton); SubscribeLocalEvent((e,c,_) => UpdateUserInterface(e,c), @@ -93,6 +96,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem return; component.LastAnalyzedArtifact = null; + component.ReadyToPrint = false; UpdateAnalyzerInformation(uid, component); } @@ -177,6 +181,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem float? completion = null; var totalTime = TimeSpan.Zero; var canScan = false; + var canPrint = false; if (component.AnalyzerEntity != null && TryComp(component.AnalyzerEntity, out var analyzer)) { artifact = analyzer.LastAnalyzedArtifact; @@ -184,6 +189,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem completion = analyzer.LastAnalyzedCompletion; totalTime = analyzer.AnalysisDuration * analyzer.AnalysisDurationMulitplier; canScan = analyzer.Contacts.Any(); + canPrint = analyzer.ReadyToPrint; } var analyzerConnected = component.AnalyzerEntity != null; @@ -192,7 +198,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem var scanning = TryComp(component.AnalyzerEntity, out var active); var remaining = active != null ? _timing.CurTime - active.StartTime : TimeSpan.Zero; - var state = new AnalysisConsoleScanUpdateState(artifact, analyzerConnected, serverConnected, canScan, + var state = new AnalysisConsoleScanUpdateState(artifact, analyzerConnected, serverConnected, canScan, canPrint, node?.Id, node?.Depth, node?.Edges.Count, node?.Triggered, node?.Effect.ID, node?.Trigger.ID, completion, scanning, remaining, totalTime); @@ -237,6 +243,68 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem activeArtifact.Scanner = component.AnalyzerEntity.Value; } + private void OnPrintButton(EntityUid uid, AnalysisConsoleComponent component, AnalysisConsolePrintButtonPressedMessage args) + { + if (component.AnalyzerEntity == null) + return; + + if (!TryComp(component.AnalyzerEntity, out var analyzer) || + analyzer.LastAnalyzedNode == null || + analyzer.LastAnalyzedCompletion == null || + !analyzer.ReadyToPrint) + { + return; + } + + analyzer.ReadyToPrint = false; + var n = analyzer.LastAnalyzedNode; + + var report = Spawn(component.ReportEntityId, Transform(uid).Coordinates); + MetaData(report).EntityName = Loc.GetString("analysis-report-title", ("id", n.Id)); + + var msg = new FormattedMessage(); + + msg.AddMarkup(Loc.GetString("analysis-console-info-id", ("id", n.Id))); + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("analysis-console-info-depth", ("depth", n.Depth))); + msg.PushNewline(); + + var activated = n.Triggered + ? "analysis-console-info-triggered-true" + : "analysis-console-info-triggered-false"; + msg.AddMarkup(Loc.GetString(activated)); + msg.PushNewline(); + + msg.PushNewline(); + var needSecondNewline = false; + if (n.Trigger.TriggerHint != null) + { + msg.AddMarkup(Loc.GetString("analysis-console-info-trigger", + ("trigger", Loc.GetString(n.Trigger.TriggerHint))) + "\n"); + needSecondNewline = true; + } + + if (n.Effect.EffectHint != null) + { + msg.AddMarkup(Loc.GetString("analysis-console-info-effect", + ("effect", Loc.GetString(n.Effect.EffectHint))) + "\n"); + needSecondNewline = true; + } + + if (needSecondNewline) + msg.PushNewline(); + + msg.AddMarkup(Loc.GetString("analysis-console-info-edges", ("edges", n.Edges.Count))); + msg.PushNewline(); + + msg.AddMarkup(Loc.GetString("analysis-console-info-completion", + ("percentage", Math.Round(analyzer.LastAnalyzedCompletion.Value * 100)))); + + _popup.PopupEntity(Loc.GetString("analysis-console-print-popup"), uid, Filter.Pvs(uid)); + _paper.SetContent(report, msg.ToMarkup()); + UpdateUserInterface(uid, component); + } + /// /// destroys the artifact and updates the server points /// @@ -333,6 +401,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem if (!Resolve(uid, ref component, ref active)) return; + component.ReadyToPrint = true; _audio.PlayPvs(component.ScanFinishedSound, uid); component.LastAnalyzedArtifact = active.Artifact; UpdateAnalyzerInformation(uid, component); diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs index ab0d43a523..60955a5381 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs @@ -158,7 +158,13 @@ public sealed partial class ArtifactSystem : EntitySystem component.CurrentNode.Triggered = true; if (component.CurrentNode.Edges.Any()) { + var undiscoveredNodes = component.CurrentNode.Edges.Where(x => !x.Discovered).ToList(); + var newNode = _random.Pick(component.CurrentNode.Edges); + if (undiscoveredNodes.Any() && _random.Prob(0.75f)) + { + newNode = _random.Pick(undiscoveredNodes); + } EnterNode(uid, ref newNode, component); } } diff --git a/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs b/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs index 2adb0391ac..51306e7b8b 100644 --- a/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs +++ b/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs @@ -18,6 +18,11 @@ public sealed class AnalysisConsoleScanButtonPressedMessage : BoundUserInterface { } +[Serializable, NetSerializable] +public sealed class AnalysisConsolePrintButtonPressedMessage : BoundUserInterfaceMessage +{ +} + [Serializable, NetSerializable] public sealed class AnalysisConsoleDestroyButtonPressedMessage : BoundUserInterfaceMessage { @@ -34,6 +39,8 @@ public sealed class AnalysisConsoleScanUpdateState : BoundUserInterfaceState public bool CanScan; + public bool CanPrint; + public int? Id; public int? Depth; @@ -54,7 +61,7 @@ public sealed class AnalysisConsoleScanUpdateState : BoundUserInterfaceState public TimeSpan TotalTime; - public AnalysisConsoleScanUpdateState(EntityUid? artifact, bool analyzerConnected, bool serverConnected, bool canScan, + public AnalysisConsoleScanUpdateState(EntityUid? artifact, bool analyzerConnected, bool serverConnected, bool canScan, bool canPrint, int? id, int? depth, int? edges, bool? triggered, string? effectProto, string? triggerProto, float? completion, bool scanning, TimeSpan timeRemaining, TimeSpan totalTime) { @@ -62,6 +69,7 @@ public sealed class AnalysisConsoleScanUpdateState : BoundUserInterfaceState AnalyzerConnected = analyzerConnected; ServerConnected = serverConnected; CanScan = canScan; + CanPrint = canPrint; Id = id; Depth = depth; diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl index 11937ea17f..5fecaeb814 100644 --- a/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl @@ -2,6 +2,8 @@ analysis-console-menu-title = analysis console analysis-console-server-list-button = Server List analysis-console-scan-button = Scan analysis-console-scan-tooltip-info = Scan artifacts to learn information about their structure. +analysis-console-print-button = Print +analysis-console-print-tooltip-info = Print out the current information about the artifact. analysis-console-destroy-button = Destroy analysis-console-destroy-button-info = Destroy artifacts to generate points based on how much has been unlocked. @@ -24,6 +26,14 @@ analysis-console-progress-text = {$seconds -> *[other] T-{$seconds} seconds } +analysis-destroy-window-title = Confirm Destruction +analysis-destroy-window-text = Destroy the artifact, converting it into research points? +analysis-destroy-window-yes = Yes +analysis-destroy-window-no = No + analyzer-artifact-component-upgrade-analysis = analysis duration +analysis-console-print-popup = The console printed out a report. analyzer-artifact-destroy-popup = The artifact disintegrated into energy! + +analysis-report-title = Artifact Report: Node {$id} \ No newline at end of file diff --git a/Resources/Prototypes/XenoArch/artifact_effects.yml b/Resources/Prototypes/XenoArch/artifact_effects.yml index 8452bad16c..a99e9e0f0f 100644 --- a/Resources/Prototypes/XenoArch/artifact_effects.yml +++ b/Resources/Prototypes/XenoArch/artifact_effects.yml @@ -262,7 +262,7 @@ effectHint: artifact-effect-hint-creation components: - type: SpawnArtifact - maxSpawns: 5 + maxSpawns: 15 consistentSpawn: false possiblePrototypes: - SilverOre1 diff --git a/Resources/Prototypes/XenoArch/artifact_triggers.yml b/Resources/Prototypes/XenoArch/artifact_triggers.yml index 51e0be3df1..81bab760e0 100644 --- a/Resources/Prototypes/XenoArch/artifact_triggers.yml +++ b/Resources/Prototypes/XenoArch/artifact_triggers.yml @@ -122,7 +122,7 @@ - type: ArtifactDamageTrigger damageTypes: - Radiation - damageThreshold: 100 + damageThreshold: 50 - type: RadiationReceiver - type: artifactTrigger