From 65acae15c02fecea533329e55ae7b2d42d11092d Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Thu, 23 Mar 2023 22:50:24 -0400 Subject: [PATCH] Make artifacts support saving (#14784) --- .../Systems/ArtifactAnalyzerSystem.cs | 23 +++-- .../Equipment/Systems/NodeScannerSystem.cs | 4 +- .../XenoArtifacts/ArtifactComponent.cs | 69 +++++--------- .../XenoArtifacts/ArtifactSystem.Actions.cs | 4 +- .../XenoArtifacts/ArtifactSystem.Commands.cs | 12 +-- .../XenoArtifacts/ArtifactSystem.Nodes.cs | 92 +++++++++++++------ .../XenoArtifacts/ArtifactSystem.cs | 83 +++++++++++------ 7 files changed, 170 insertions(+), 117 deletions(-) diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs index 5197f2ca36..6c1bb31833 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs @@ -14,11 +14,13 @@ using Content.Shared.MachineLinking.Events; using Content.Shared.Popups; using Content.Shared.Research.Components; using Content.Shared.Xenoarchaeology.Equipment; +using Content.Shared.Xenoarchaeology.XenoArtifacts; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Physics.Events; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -31,6 +33,7 @@ namespace Content.Server.Xenoarchaeology.Equipment.Systems; public sealed class ArtifactAnalyzerSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambienntSound = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; @@ -74,7 +77,8 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem { base.Update(frameTime); - foreach (var (active, scan) in EntityQuery()) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var active, out var scan)) { if (scan.Console != null) UpdateUserInterface(scan.Console.Value); @@ -82,7 +86,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem if (_timing.CurTime - active.StartTime < (scan.AnalysisDuration * scan.AnalysisDurationMulitplier)) continue; - FinishScan(scan.Owner, scan, active); + FinishScan(uid, scan, active); } } @@ -139,7 +143,9 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem } else if (TryComp(component.LastAnalyzedArtifact, out var artifact)) { - var lastNode = (ArtifactNode?) artifact.CurrentNode?.Clone(); + var lastNode = artifact.CurrentNodeId == null + ? null + : (ArtifactNode?) _artifact.GetNodeFromId(artifact.CurrentNodeId.Value, artifact).Clone(); component.LastAnalyzedNode = lastNode; component.LastAnalyzerPointValue = _artifact.GetResearchPointValue(component.LastAnalyzedArtifact.Value, artifact); } @@ -298,17 +304,20 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem msg.PushNewline(); var needSecondNewline = false; - if (n.Trigger.TriggerHint != null) + + var triggerProto = _prototype.Index(n.Trigger); + if (triggerProto.TriggerHint != null) { msg.AddMarkup(Loc.GetString("analysis-console-info-trigger", - ("trigger", Loc.GetString(n.Trigger.TriggerHint))) + "\n"); + ("trigger", Loc.GetString(triggerProto.TriggerHint))) + "\n"); needSecondNewline = true; } - if (n.Effect.EffectHint != null) + var effectproto = _prototype.Index(n.Effect); + if (effectproto.EffectHint != null) { msg.AddMarkup(Loc.GetString("analysis-console-info-effect", - ("effect", Loc.GetString(n.Effect.EffectHint))) + "\n"); + ("effect", Loc.GetString(effectproto.EffectHint))) + "\n"); needSecondNewline = true; } diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/NodeScannerSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/NodeScannerSystem.cs index 1b08696956..928de35711 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/NodeScannerSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/NodeScannerSystem.cs @@ -23,7 +23,7 @@ public sealed class NodeScannerSystem : EntitySystem if (!args.CanReach || args.Target == null) return; - if (!TryComp(args.Target, out var artifact) || artifact.CurrentNode == null) + if (!TryComp(args.Target, out var artifact) || artifact.CurrentNodeId == null) return; if (args.Handled) @@ -33,6 +33,6 @@ public sealed class NodeScannerSystem : EntitySystem var target = args.Target.Value; _useDelay.BeginDelay(uid); _popupSystem.PopupEntity(Loc.GetString("node-scan-popup", - ("id", $"{artifact.CurrentNode.Id}")), target); + ("id", $"{artifact.CurrentNodeId}")), target); } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactComponent.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactComponent.cs index 7a10d85532..21dfb084e9 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactComponent.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Xenoarchaeology.XenoArtifacts; -using Robust.Shared.Serialization.TypeSerializers.Implementations; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Xenoarchaeology.XenoArtifacts; @@ -7,16 +8,16 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts; public sealed class ArtifactComponent : Component { /// - /// The artifact's node tree. + /// Every node contained in the tree /// - [ViewVariables] - public ArtifactTree? NodeTree; + [DataField("nodeTree"), ViewVariables] + public List NodeTree = new(); /// /// The current node the artifact is on. /// - [ViewVariables] - public ArtifactNode? CurrentNode; + [DataField("currentNodeId"), ViewVariables] + public int? CurrentNodeId; #region Node Tree Gen /// @@ -35,21 +36,20 @@ public sealed class ArtifactComponent : Component /// /// Cooldown time between artifact activations (in seconds). /// - [DataField("timer", customTypeSerializer: typeof(TimespanSerializer))] - [ViewVariables(VVAccess.ReadWrite)] + [DataField("timer"), ViewVariables(VVAccess.ReadWrite)] public TimeSpan CooldownTime = TimeSpan.FromSeconds(5); /// /// Is this artifact under some suppression device? /// f true, will ignore all trigger activations attempts. /// - [ViewVariables(VVAccess.ReadWrite)] + [DataField("isSuppressed"), ViewVariables(VVAccess.ReadWrite)] public bool IsSuppressed; /// /// The last time the artifact was activated. /// - [DataField("lastActivationTime", customTypeSerializer: typeof(TimespanSerializer))] + [DataField("lastActivationTime", customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan LastActivationTime; /// @@ -72,25 +72,6 @@ public sealed class ArtifactComponent : Component public float PointDangerMultiplier = 1.35f; } -/// -/// A tree of nodes. -/// -[DataDefinition] -public sealed class ArtifactTree -{ - /// - /// The first node of the tree - /// - [ViewVariables] - public ArtifactNode StartNode = default!; - - /// - /// Every node contained in the tree - /// - [ViewVariables] - public readonly List AllNodes = new(); -} - /// /// A single "node" of an artifact that contains various data about it. /// @@ -98,51 +79,51 @@ public sealed class ArtifactTree public sealed class ArtifactNode : ICloneable { /// - /// A numeric id corresponding to each node. used for display purposes + /// A numeric id corresponding to each node. /// - [ViewVariables] + [DataField("id"), ViewVariables] public int Id; /// /// how "deep" into the node tree. used for generation and price/value calculations /// - [ViewVariables] - public int Depth = 0; + [DataField("depth"), ViewVariables] + public int Depth; /// /// A list of surrounding nodes. Used for tree traversal /// - [ViewVariables] - public List Edges = new(); + [DataField("edges"), ViewVariables] + public HashSet Edges = new(); /// /// Whether or not the node has been entered /// - [ViewVariables(VVAccess.ReadWrite)] - public bool Discovered = false; + [DataField("discovered"), ViewVariables(VVAccess.ReadWrite)] + public bool Discovered; /// /// The trigger for the node /// - [ViewVariables] - public ArtifactTriggerPrototype Trigger = default!; + [DataField("trigger", customTypeSerializer: typeof(PrototypeIdSerializer), required: true), ViewVariables] + public string Trigger = default!; /// /// Whether or not the node has been triggered /// - [ViewVariables(VVAccess.ReadWrite)] - public bool Triggered = false; + [DataField("triggered"), ViewVariables(VVAccess.ReadWrite)] + public bool Triggered; /// /// The effect when the node is activated /// - [ViewVariables] - public ArtifactEffectPrototype Effect = default!; + [DataField("effect", customTypeSerializer: typeof(PrototypeIdSerializer), required: true), ViewVariables] + public string Effect = default!; /// /// Used for storing cumulative information about nodes /// - [ViewVariables] + [DataField("nodeData"), ViewVariables] public Dictionary NodeData = new(); public object Clone() diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Actions.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Actions.cs index 3f84fcc6ac..69f9450a4f 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Actions.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Actions.cs @@ -42,10 +42,10 @@ public partial class ArtifactSystem private void OnSelfActivate(EntityUid uid, ArtifactComponent component, ArtifactSelfActivateEvent args) { - if (component.CurrentNode == null) + if (component.CurrentNodeId == null) return; - var curNode = component.CurrentNode.Id; + var curNode = GetNodeFromId(component.CurrentNodeId.Value, component).Id; _popup.PopupEntity(Loc.GetString("activate-artifact-popup-self", ("node", curNode)), uid, uid); TryActivateArtifact(uid, uid, component); diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Commands.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Commands.cs index ddb1573b32..37f974f6b0 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Commands.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Commands.cs @@ -28,10 +28,10 @@ public partial class ArtifactSystem if (!EntityUid.TryParse(args[0], out var uid) || ! int.TryParse(args[1], out var id)) return; - if (!TryComp(uid, out var artifact) || artifact.NodeTree == null) + if (!TryComp(uid, out var artifact)) return; - if (artifact.NodeTree.AllNodes.FirstOrDefault(n => n.Id == id) is { } node) + if (artifact.NodeTree.FirstOrDefault(n => n.Id == id) is { } node) { EnterNode(uid, ref node); } @@ -41,9 +41,9 @@ public partial class ArtifactSystem { if (args.Length == 2 && EntityUid.TryParse(args[0], out var uid)) { - if (TryComp(uid, out var artifact) && artifact.NodeTree != null) + if (TryComp(uid, out var artifact)) { - return CompletionResult.FromHintOptions(artifact.NodeTree.AllNodes.Select(s => s.Id.ToString()), ""); + return CompletionResult.FromHintOptions(artifact.NodeTree.Select(s => s.Id.ToString()), ""); } } @@ -59,10 +59,10 @@ public partial class ArtifactSystem if (!EntityUid.TryParse(args[0], out var uid)) return; - if (!TryComp(uid, out var artifact) || artifact.NodeTree == null) + if (!TryComp(uid, out var artifact)) return; var pointSum = GetResearchPointValue(uid, artifact, true); - shell.WriteLine($"Max point value for {ToPrettyString(uid)} with {artifact.NodeTree.AllNodes.Count} nodes: {pointSum}"); + shell.WriteLine($"Max point value for {ToPrettyString(uid)} with {artifact.NodeTree.Count} nodes: {pointSum}"); } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs index 5c83440e5f..54b83f2514 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; using Content.Shared.Xenoarchaeology.XenoArtifacts; +using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization.Manager; @@ -15,13 +16,15 @@ public sealed partial class ArtifactSystem private const int MaxEdgesPerNode = 4; + private readonly HashSet _usedNodeIds = new(); + /// /// Generate an Artifact tree with fully developed nodes. /// /// - /// The tree being generated. + /// /// The amount of nodes it has. - private void GenerateArtifactNodeTree(EntityUid artifact, ref ArtifactTree tree, int nodeAmount) + private void GenerateArtifactNodeTree(EntityUid artifact, ref List allNodes, int nodeAmount) { if (nodeAmount < 1) { @@ -29,19 +32,36 @@ public sealed partial class ArtifactSystem return; } - var uninitializedNodes = new List { new() }; - tree.StartNode = uninitializedNodes.First(); //the first node + _usedNodeIds.Clear(); + + var rootNode = new ArtifactNode + { + Id = GetValidNodeId() + }; + var uninitializedNodes = new List { rootNode }; while (uninitializedNodes.Any()) { - GenerateNode(artifact, ref uninitializedNodes, ref tree, nodeAmount); + GenerateNode(artifact, ref uninitializedNodes, ref allNodes, nodeAmount); } } + private int GetValidNodeId() + { + var id = _random.Next(10000, 100000); + while (_usedNodeIds.Contains(id)) + { + id = _random.Next(10000, 100000); + } + + _usedNodeIds.Add(id); + return id; + } + /// /// Generate an individual node on the tree. /// - private void GenerateNode(EntityUid artifact, ref List uninitializedNodes, ref ArtifactTree tree, int targetNodeAmount) + private void GenerateNode(EntityUid artifact, ref List uninitializedNodes, ref List allNodes, int targetNodeAmount) { if (!uninitializedNodes.Any()) return; @@ -49,13 +69,10 @@ public sealed partial class ArtifactSystem var node = uninitializedNodes.First(); uninitializedNodes.Remove(node); - //random 5-digit number - node.Id = _random.Next(10000, 100000); - //Generate the connected nodes - var maxEdges = Math.Max(1, targetNodeAmount - tree.AllNodes.Count - uninitializedNodes.Count - 1); + var maxEdges = Math.Max(1, targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1); maxEdges = Math.Min(maxEdges, MaxEdgesPerNode); - var minEdges = Math.Clamp(targetNodeAmount - tree.AllNodes.Count - uninitializedNodes.Count - 1, 0, 1); + var minEdges = Math.Clamp(targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1, 0, 1); var edgeAmount = _random.Next(minEdges, maxEdges); @@ -63,10 +80,11 @@ public sealed partial class ArtifactSystem { var neighbor = new ArtifactNode { - Depth = node.Depth + 1 + Depth = node.Depth + 1, + Id = GetValidNodeId() }; - node.Edges.Add(neighbor); - neighbor.Edges.Add(node); + node.Edges.Add(neighbor.Id); + neighbor.Edges.Add(node.Id); uninitializedNodes.Add(neighbor); } @@ -74,13 +92,13 @@ public sealed partial class ArtifactSystem node.Trigger = GetRandomTrigger(artifact, ref node); node.Effect = GetRandomEffect(artifact, ref node); - tree.AllNodes.Add(node); + allNodes.Add(node); } //yeah these two functions are near duplicates but i don't //want to implement an interface or abstract parent - private ArtifactTriggerPrototype GetRandomTrigger(EntityUid artifact, ref ArtifactNode node) + private string GetRandomTrigger(EntityUid artifact, ref ArtifactNode node) { var allTriggers = _prototype.EnumeratePrototypes() .Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList(); @@ -91,10 +109,10 @@ public sealed partial class ArtifactSystem var targetTriggers = allTriggers .Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList(); - return _random.Pick(targetTriggers); + return _random.Pick(targetTriggers).ID; } - private ArtifactEffectPrototype GetRandomEffect(EntityUid artifact, ref ArtifactNode node) + private string GetRandomEffect(EntityUid artifact, ref ArtifactNode node) { var allEffects = _prototype.EnumeratePrototypes() .Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList(); @@ -105,7 +123,7 @@ public sealed partial class ArtifactSystem var targetEffects = allEffects .Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList(); - return _random.Pick(targetEffects); + return _random.Pick(targetEffects).ID; } /// @@ -156,14 +174,17 @@ public sealed partial class ArtifactSystem if (!Resolve(uid, ref component)) return; - if (component.CurrentNode != null) + if (component.CurrentNodeId != null) { ExitNode(uid, component); } - component.CurrentNode = node; + component.CurrentNodeId = node.Id; + + var trigger = _prototype.Index(node.Trigger); + var effect = _prototype.Index(node.Effect); - var allComponents = node.Effect.Components.Concat(node.Effect.PermanentComponents).Concat(node.Trigger.Components); + var allComponents = effect.Components.Concat(effect.PermanentComponents).Concat(trigger.Components); foreach (var (name, entry) in allComponents) { var reg = _componentFactory.GetRegistration(name); @@ -171,7 +192,7 @@ public sealed partial class ArtifactSystem if (node.Discovered && EntityManager.HasComponent(uid, reg.Type)) { // Don't re-add permanent components unless this is the first time you've entered this node - if (node.Effect.PermanentComponents.ContainsKey(name)) + if (effect.PermanentComponents.ContainsKey(name)) continue; EntityManager.RemoveComponent(uid, reg.Type); @@ -187,7 +208,7 @@ public sealed partial class ArtifactSystem } node.Discovered = true; - RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNode.Id)); + RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNodeId.Value)); } /// @@ -198,16 +219,31 @@ public sealed partial class ArtifactSystem if (!Resolve(uid, ref component)) return; - var node = component.CurrentNode; - if (node == null) + if (component.CurrentNodeId == null) return; + var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component); + + var trigger = _prototype.Index(currentNode.Trigger); + var effect = _prototype.Index(currentNode.Effect); - foreach (var name in node.Effect.Components.Keys.Concat(node.Trigger.Components.Keys)) + foreach (var name in effect.Components.Keys.Concat(trigger.Components.Keys)) { var comp = _componentFactory.GetRegistration(name); EntityManager.RemoveComponentDeferred(uid, comp.Type); } - component.CurrentNode = null; + component.CurrentNodeId = null; + } + + [PublicAPI] + public ArtifactNode GetNodeFromId(int id, ArtifactComponent component) + { + return component.NodeTree.First(x => x.Id == id); + } + + [PublicAPI] + public ArtifactNode GetNodeFromId(int id, IEnumerable nodes) + { + return nodes.First(x => x.Id == id); } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs index b0a12c9509..d11f835079 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Power.EntitySystems; using Content.Server.Xenoarchaeology.Equipment.Components; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; +using Content.Shared.Xenoarchaeology.XenoArtifacts; using JetBrains.Annotations; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -46,13 +47,10 @@ public sealed partial class ArtifactSystem : EntitySystem /// private void GetPrice(EntityUid uid, ArtifactComponent component, ref PriceCalculationEvent args) { - if (component.NodeTree == null) - return; - - var price = component.NodeTree.AllNodes.Sum(x => GetNodePrice(x, component)); + var price = component.NodeTree.Sum(x => GetNodePrice(x, component)); // 25% bonus for fully exploring every node. - var fullyExploredBonus = component.NodeTree.AllNodes.Any(x => !x.Triggered) ? 1 : 1.25f; + var fullyExploredBonus = component.NodeTree.Any(x => !x.Triggered) ? 1 : 1.25f; args.Price =+ price * fullyExploredBonus; } @@ -62,10 +60,13 @@ public sealed partial class ArtifactSystem : EntitySystem if (!node.Discovered) //no money for undiscovered nodes. return 0; + var triggerProto = _prototype.Index(node.Trigger); + var effectProto = _prototype.Index(node.Effect); + //quarter price if not triggered var priceMultiplier = node.Triggered ? 1f : 0.25f; //the danger is the average of node depth, effect danger, and trigger danger. - var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3; + var nodeDanger = (node.Depth + effectProto.TargetDepth + triggerProto.TargetDepth) / 3; var price = MathF.Pow(2f, nodeDanger) * component.PricePerNode * priceMultiplier; return price; @@ -86,11 +87,11 @@ public sealed partial class ArtifactSystem : EntitySystem /// public int GetResearchPointValue(EntityUid uid, ArtifactComponent? component = null, bool getMaxPrice = false) { - if (!Resolve(uid, ref component) || component.NodeTree == null) + if (!Resolve(uid, ref component)) return 0; - var sumValue = component.NodeTree.AllNodes.Sum(n => GetNodePointValue(n, component, getMaxPrice)); - var fullyExploredBonus = component.NodeTree.AllNodes.All(x => x.Triggered) || getMaxPrice ? 1.25f : 1; + var sumValue = component.NodeTree.Sum(n => GetNodePointValue(n, component, getMaxPrice)); + var fullyExploredBonus = component.NodeTree.All(x => x.Triggered) || getMaxPrice ? 1.25f : 1; var pointValue = (int) (sumValue * fullyExploredBonus); return pointValue; @@ -109,7 +110,11 @@ public sealed partial class ArtifactSystem : EntitySystem valueDeduction = !node.Triggered ? 0.25f : 1; } - var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3; + + var triggerProto = _prototype.Index(node.Trigger); + var effectProto = _prototype.Index(node.Effect); + + var nodeDanger = (node.Depth + effectProto.TargetDepth + triggerProto.TargetDepth) / 3; return component.PointsPerNode * MathF.Pow(component.PointDangerMultiplier, nodeDanger) * valueDeduction; } @@ -121,10 +126,9 @@ public sealed partial class ArtifactSystem : EntitySystem { var nodeAmount = _random.Next(component.NodesMin, component.NodesMax); - component.NodeTree = new ArtifactTree(); - GenerateArtifactNodeTree(uid, ref component.NodeTree, nodeAmount); - EnterNode(uid, ref component.NodeTree.StartNode, component); + var firstNode = GetRootNode(component.NodeTree); + EnterNode(uid, ref firstNode, component); } /// @@ -162,7 +166,7 @@ public sealed partial class ArtifactSystem : EntitySystem { if (!Resolve(uid, ref component)) return; - if (component.CurrentNode == null) + if (component.CurrentNodeId == null) return; component.LastActivationTime = _gameTiming.CurTime; @@ -173,8 +177,10 @@ public sealed partial class ArtifactSystem : EntitySystem }; RaiseLocalEvent(uid, ev, true); - component.CurrentNode.Triggered = true; - if (component.CurrentNode.Edges.Any()) + var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component); + + currentNode.Triggered = true; + if (currentNode.Edges.Any()) { var newNode = GetNewNode(uid, component); if (newNode == null) @@ -185,10 +191,18 @@ public sealed partial class ArtifactSystem : EntitySystem private ArtifactNode? GetNewNode(EntityUid uid, ArtifactComponent component) { - if (component.CurrentNode == null) + if (component.CurrentNodeId == null) return null; - var allNodes = component.CurrentNode.Edges; + var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component); + + var allNodes = currentNode.Edges; + Logger.Debug($"our node: {currentNode.Id}"); + Logger.Debug("other nodes:"); + foreach (var other in allNodes) + { + Logger.Debug($"{other}"); + } if (TryComp(uid, out var bias) && TryComp(bias.Provider, out var trav) && @@ -198,26 +212,26 @@ public sealed partial class ArtifactSystem : EntitySystem switch (trav.BiasDirection) { case BiasDirection.In: - var foo = allNodes.Where(x => x.Depth < component.CurrentNode.Depth).ToList(); + var foo = allNodes.Where(x => GetNodeFromId(x, component).Depth < currentNode.Depth).ToHashSet(); if (foo.Any()) allNodes = foo; break; case BiasDirection.Out: - var bar = allNodes.Where(x => x.Depth > component.CurrentNode.Depth).ToList(); + var bar = allNodes.Where(x => GetNodeFromId(x, component).Depth > currentNode.Depth).ToHashSet(); if (bar.Any()) allNodes = bar; break; } } - var undiscoveredNodes = allNodes.Where(x => !x.Discovered).ToList(); + var undiscoveredNodes = allNodes.Where(x => GetNodeFromId(x, component).Discovered).ToList(); var newNode = _random.Pick(allNodes); if (undiscoveredNodes.Any() && _random.Prob(0.75f)) { newNode = _random.Pick(undiscoveredNodes); } - return newNode; + return GetNodeFromId(newNode, component); } /// @@ -236,10 +250,11 @@ public sealed partial class ArtifactSystem : EntitySystem if (!Resolve(uid, ref component)) return false; - if (component.CurrentNode == null) + if (component.CurrentNodeId == null) return false; + var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component); - if (component.CurrentNode.NodeData.TryGetValue(key, out var dat) && dat is T value) + if (currentNode.NodeData.TryGetValue(key, out var dat) && dat is T value) { data = value; return true; @@ -260,10 +275,21 @@ public sealed partial class ArtifactSystem : EntitySystem if (!Resolve(uid, ref component)) return; - if (component.CurrentNode == null) + if (component.CurrentNodeId == null) return; + var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component); + + currentNode.NodeData[key] = value; + } - component.CurrentNode.NodeData[key] = value; + /// + /// Gets the base node (depth 0) of an artifact's node graph + /// + /// + /// + public ArtifactNode GetRootNode(List allNodes) + { + return allNodes.First(n => n.Depth == 0); } /// @@ -271,10 +297,11 @@ public sealed partial class ArtifactSystem : EntitySystem /// private void OnRoundEnd(RoundEndTextAppendEvent ev) { - foreach (var artifactComp in EntityQuery()) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var artifactComp)) { artifactComp.CooldownTime = TimeSpan.Zero; - var timerTrigger = EnsureComp(artifactComp.Owner); + var timerTrigger = EnsureComp(ent); timerTrigger.ActivationRate = TimeSpan.FromSeconds(0.5); //HAHAHAHAHAHAHAHAHAH -emo } } -- 2.51.2