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;
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!;
{
base.Update(frameTime);
- foreach (var (active, scan) in EntityQuery<ActiveArtifactAnalyzerComponent, ArtifactAnalyzerComponent>())
+ var query = EntityQueryEnumerator<ActiveArtifactAnalyzerComponent, ArtifactAnalyzerComponent>();
+ while (query.MoveNext(out var uid, out var active, out var scan))
{
if (scan.Console != null)
UpdateUserInterface(scan.Console.Value);
if (_timing.CurTime - active.StartTime < (scan.AnalysisDuration * scan.AnalysisDurationMulitplier))
continue;
- FinishScan(scan.Owner, scan, active);
+ FinishScan(uid, scan, active);
}
}
}
else if (TryComp<ArtifactComponent>(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);
}
msg.PushNewline();
var needSecondNewline = false;
- if (n.Trigger.TriggerHint != null)
+
+ var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(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<ArtifactEffectPrototype>(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;
}
if (!args.CanReach || args.Target == null)
return;
- if (!TryComp<ArtifactComponent>(args.Target, out var artifact) || artifact.CurrentNode == null)
+ if (!TryComp<ArtifactComponent>(args.Target, out var artifact) || artifact.CurrentNodeId == null)
return;
if (args.Handled)
var target = args.Target.Value;
_useDelay.BeginDelay(uid);
_popupSystem.PopupEntity(Loc.GetString("node-scan-popup",
- ("id", $"{artifact.CurrentNode.Id}")), target);
+ ("id", $"{artifact.CurrentNodeId}")), target);
}
}
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;
public sealed class ArtifactComponent : Component
{
/// <summary>
- /// The artifact's node tree.
+ /// Every node contained in the tree
/// </summary>
- [ViewVariables]
- public ArtifactTree? NodeTree;
+ [DataField("nodeTree"), ViewVariables]
+ public List<ArtifactNode> NodeTree = new();
/// <summary>
/// The current node the artifact is on.
/// </summary>
- [ViewVariables]
- public ArtifactNode? CurrentNode;
+ [DataField("currentNodeId"), ViewVariables]
+ public int? CurrentNodeId;
#region Node Tree Gen
/// <summary>
/// <summary>
/// Cooldown time between artifact activations (in seconds).
/// </summary>
- [DataField("timer", customTypeSerializer: typeof(TimespanSerializer))]
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("timer"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan CooldownTime = TimeSpan.FromSeconds(5);
/// <summary>
/// Is this artifact under some suppression device?
/// f true, will ignore all trigger activations attempts.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("isSuppressed"), ViewVariables(VVAccess.ReadWrite)]
public bool IsSuppressed;
/// <summary>
/// The last time the artifact was activated.
/// </summary>
- [DataField("lastActivationTime", customTypeSerializer: typeof(TimespanSerializer))]
+ [DataField("lastActivationTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan LastActivationTime;
/// <summary>
public float PointDangerMultiplier = 1.35f;
}
-/// <summary>
-/// A tree of nodes.
-/// </summary>
-[DataDefinition]
-public sealed class ArtifactTree
-{
- /// <summary>
- /// The first node of the tree
- /// </summary>
- [ViewVariables]
- public ArtifactNode StartNode = default!;
-
- /// <summary>
- /// Every node contained in the tree
- /// </summary>
- [ViewVariables]
- public readonly List<ArtifactNode> AllNodes = new();
-}
-
/// <summary>
/// A single "node" of an artifact that contains various data about it.
/// </summary>
public sealed class ArtifactNode : ICloneable
{
/// <summary>
- /// A numeric id corresponding to each node. used for display purposes
+ /// A numeric id corresponding to each node.
/// </summary>
- [ViewVariables]
+ [DataField("id"), ViewVariables]
public int Id;
/// <summary>
/// how "deep" into the node tree. used for generation and price/value calculations
/// </summary>
- [ViewVariables]
- public int Depth = 0;
+ [DataField("depth"), ViewVariables]
+ public int Depth;
/// <summary>
/// A list of surrounding nodes. Used for tree traversal
/// </summary>
- [ViewVariables]
- public List<ArtifactNode> Edges = new();
+ [DataField("edges"), ViewVariables]
+ public HashSet<int> Edges = new();
/// <summary>
/// Whether or not the node has been entered
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- public bool Discovered = false;
+ [DataField("discovered"), ViewVariables(VVAccess.ReadWrite)]
+ public bool Discovered;
/// <summary>
/// The trigger for the node
/// </summary>
- [ViewVariables]
- public ArtifactTriggerPrototype Trigger = default!;
+ [DataField("trigger", customTypeSerializer: typeof(PrototypeIdSerializer<ArtifactTriggerPrototype>), required: true), ViewVariables]
+ public string Trigger = default!;
/// <summary>
/// Whether or not the node has been triggered
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- public bool Triggered = false;
+ [DataField("triggered"), ViewVariables(VVAccess.ReadWrite)]
+ public bool Triggered;
/// <summary>
/// The effect when the node is activated
/// </summary>
- [ViewVariables]
- public ArtifactEffectPrototype Effect = default!;
+ [DataField("effect", customTypeSerializer: typeof(PrototypeIdSerializer<ArtifactEffectPrototype>), required: true), ViewVariables]
+ public string Effect = default!;
/// <summary>
/// Used for storing cumulative information about nodes
/// </summary>
- [ViewVariables]
+ [DataField("nodeData"), ViewVariables]
public Dictionary<string, object> NodeData = new();
public object Clone()
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);
if (!EntityUid.TryParse(args[0], out var uid) || ! int.TryParse(args[1], out var id))
return;
- if (!TryComp<ArtifactComponent>(uid, out var artifact) || artifact.NodeTree == null)
+ if (!TryComp<ArtifactComponent>(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);
}
{
if (args.Length == 2 && EntityUid.TryParse(args[0], out var uid))
{
- if (TryComp<ArtifactComponent>(uid, out var artifact) && artifact.NodeTree != null)
+ if (TryComp<ArtifactComponent>(uid, out var artifact))
{
- return CompletionResult.FromHintOptions(artifact.NodeTree.AllNodes.Select(s => s.Id.ToString()), "<node id>");
+ return CompletionResult.FromHintOptions(artifact.NodeTree.Select(s => s.Id.ToString()), "<node id>");
}
}
if (!EntityUid.TryParse(args[0], out var uid))
return;
- if (!TryComp<ArtifactComponent>(uid, out var artifact) || artifact.NodeTree == null)
+ if (!TryComp<ArtifactComponent>(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}");
}
}
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;
private const int MaxEdgesPerNode = 4;
+ private readonly HashSet<int> _usedNodeIds = new();
+
/// <summary>
/// Generate an Artifact tree with fully developed nodes.
/// </summary>
/// <param name="artifact"></param>
- /// <param name="tree">The tree being generated.</param>
+ /// <param name="allNodes"></param>
/// <param name="nodeAmount">The amount of nodes it has.</param>
- private void GenerateArtifactNodeTree(EntityUid artifact, ref ArtifactTree tree, int nodeAmount)
+ private void GenerateArtifactNodeTree(EntityUid artifact, ref List<ArtifactNode> allNodes, int nodeAmount)
{
if (nodeAmount < 1)
{
return;
}
- var uninitializedNodes = new List<ArtifactNode> { new() };
- tree.StartNode = uninitializedNodes.First(); //the first node
+ _usedNodeIds.Clear();
+
+ var rootNode = new ArtifactNode
+ {
+ Id = GetValidNodeId()
+ };
+ var uninitializedNodes = new List<ArtifactNode> { 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;
+ }
+
/// <summary>
/// Generate an individual node on the tree.
/// </summary>
- private void GenerateNode(EntityUid artifact, ref List<ArtifactNode> uninitializedNodes, ref ArtifactTree tree, int targetNodeAmount)
+ private void GenerateNode(EntityUid artifact, ref List<ArtifactNode> uninitializedNodes, ref List<ArtifactNode> allNodes, int targetNodeAmount)
{
if (!uninitializedNodes.Any())
return;
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);
{
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);
}
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<ArtifactTriggerPrototype>()
.Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList();
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<ArtifactEffectPrototype>()
.Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList();
var targetEffects = allEffects
.Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList();
- return _random.Pick(targetEffects);
+ return _random.Pick(targetEffects).ID;
}
/// <remarks>
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<ArtifactTriggerPrototype>(node.Trigger);
+ var effect = _prototype.Index<ArtifactEffectPrototype>(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);
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);
}
node.Discovered = true;
- RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNode.Id));
+ RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNodeId.Value));
}
/// <summary>
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<ArtifactTriggerPrototype>(currentNode.Trigger);
+ var effect = _prototype.Index<ArtifactEffectPrototype>(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<ArtifactNode> nodes)
+ {
+ return nodes.First(x => x.Id == id);
}
}
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;
/// </remarks>
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;
}
if (!node.Discovered) //no money for undiscovered nodes.
return 0;
+ var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
+ var effectProto = _prototype.Index<ArtifactEffectPrototype>(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;
/// </remarks>
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;
valueDeduction = !node.Triggered ? 0.25f : 1;
}
- var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3;
+
+ var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
+ var effectProto = _prototype.Index<ArtifactEffectPrototype>(node.Effect);
+
+ var nodeDanger = (node.Depth + effectProto.TargetDepth + triggerProto.TargetDepth) / 3;
return component.PointsPerNode * MathF.Pow(component.PointDangerMultiplier, nodeDanger) * valueDeduction;
}
{
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);
}
/// <summary>
{
if (!Resolve(uid, ref component))
return;
- if (component.CurrentNode == null)
+ if (component.CurrentNodeId == null)
return;
component.LastActivationTime = _gameTiming.CurTime;
};
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)
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<BiasedArtifactComponent>(uid, out var bias) &&
TryComp<TraversalDistorterComponent>(bias.Provider, out var trav) &&
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);
}
/// <summary>
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;
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;
+ /// <summary>
+ /// Gets the base node (depth 0) of an artifact's node graph
+ /// </summary>
+ /// <param name="allNodes"></param>
+ /// <returns></returns>
+ public ArtifactNode GetRootNode(List<ArtifactNode> allNodes)
+ {
+ return allNodes.First(n => n.Depth == 0);
}
/// <summary>
/// </summary>
private void OnRoundEnd(RoundEndTextAppendEvent ev)
{
- foreach (var artifactComp in EntityQuery<ArtifactComponent>())
+ var query = EntityQueryEnumerator<ArtifactComponent>();
+ while (query.MoveNext(out var ent, out var artifactComp))
{
artifactComp.CooldownTime = TimeSpan.Zero;
- var timerTrigger = EnsureComp<ArtifactTimerTriggerComponent>(artifactComp.Owner);
+ var timerTrigger = EnsureComp<ArtifactTimerTriggerComponent>(ent);
timerTrigger.ActivationRate = TimeSpan.FromSeconds(0.5); //HAHAHAHAHAHAHAHAHAH -emo
}
}