diff --git a/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs b/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs
index 169147de0c..3d7de10c32 100644
--- a/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs
+++ b/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs
@@ -4,7 +4,6 @@ using Content.Server.Xenoarchaeology.Artifact;
using Content.Shared.Administration;
using Content.Shared.Toolshed.TypeParsers.XenoArtifact;
using Content.Shared.Xenoarchaeology.Artifact.Components;
-using Content.Shared.Xenoarchaeology.Artifact.Prototypes;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
@@ -116,15 +115,18 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
/// Unlocks all nodes of artifact.
[CommandImplementation("unlockallnodes")]
- public void UnlockAllNodes([PipedArgument] EntityUid artifactEntityUid)
+ public void UnlockAllNodes([PipedArgument] IEnumerable artifactUids)
{
_artifact ??= Sys();
- var comp = Comp(artifactEntityUid);
-
- var nodes = _artifact.GetAllNodes((artifactEntityUid, comp));
- foreach (var node in nodes)
+ foreach (var artifactUid in artifactUids)
{
- _artifact.SetNodeUnlocked((node, node.Comp));
+ var comp = Comp(artifactUid);
+
+ var nodes = _artifact.GetAllNodes((artifactUid, comp));
+ foreach (var node in nodes)
+ {
+ _artifact.SetNodeUnlocked((node, node.Comp));
+ }
}
}
@@ -134,8 +136,8 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
[CommandImplementation("createnode")]
public void CreateNodeNew(
[CommandArgument] Entity artifact,
- [CommandArgument(typeof(XenoEffectParser))] ProtoId effect,
- [CommandArgument] ProtoId trigger
+ [CommandArgument(typeof(XenoArtifactEffectParser))] ProtoId effect,
+ [CommandArgument(typeof(XenoArtifactTriggerParser))] ProtoId trigger
)
{
CreateNode(artifact, effect, trigger);
@@ -145,8 +147,8 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
[CommandImplementation("createnodeatdepth")]
public void CreateNodeAtDepth(
[CommandArgument(typeof(XenoArtifactNodeParser))] (Entity Artifact, Entity Node) tuple,
- [CommandArgument(typeof(XenoEffectParser))] ProtoId effect,
- [CommandArgument] ProtoId trigger
+ [CommandArgument(typeof(XenoArtifactEffectParser))] ProtoId effect,
+ [CommandArgument(typeof(XenoArtifactTriggerParser))] ProtoId trigger
)
{
CreateNode(tuple.Artifact, effect, trigger, tuple.Node);
@@ -157,8 +159,8 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
public void SpawnArtifactWithNode(
[CommandArgument] ICommonSession target,
[CommandArgument(typeof(XenoArtifactTypeParser))] ProtoId artifactType,
- [CommandArgument(typeof(XenoEffectParser))] ProtoId effect,
- [CommandArgument] ProtoId trigger
+ [CommandArgument(typeof(XenoArtifactEffectParser))] ProtoId effect,
+ [CommandArgument(typeof(XenoArtifactTriggerParser))] ProtoId trigger
)
{
if (target.AttachedEntity == null)
@@ -215,7 +217,7 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
private void CreateNode(
Entity artifact,
ProtoId effect,
- ProtoId trigger,
+ ProtoId trigger,
Entity? node = null
)
{
diff --git a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.ProcGen.cs b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.ProcGen.cs
index 971c19c50f..f112512944 100644
--- a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.ProcGen.cs
+++ b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.ProcGen.cs
@@ -1,80 +1,53 @@
-using System.Linq;
-using Content.Shared.Random.Helpers;
-using Content.Shared.Whitelist;
+using Content.Shared.EntityTable;
+using Content.Shared.EntityTable.Conditions;
using Content.Shared.Xenoarchaeology.Artifact.Components;
-using Content.Shared.Xenoarchaeology.Artifact.Prototypes;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using System.Linq;
namespace Content.Server.Xenoarchaeology.Artifact;
public sealed partial class XenoArtifactSystem
{
- [Dependency] private EntityWhitelistSystem _entityWhitelist = default!;
+ [Dependency] private EntityTableSystem _entityTable = default!;
+
+ ///
+ /// Trigger for fallback scenario, when artifact acquired no trigger when generating artifact.
+ ///
+ private static readonly EntProtoId DummyTrigger = "TriggerExamine";
private void GenerateArtifactStructure(Entity ent)
{
var nodeCount = ent.Comp.NodeCount.Next(RobustRandom);
- var triggerPool = CreateTriggerPool(ent, nodeCount);
+
// trigger pool could be smaller, then requested node count
- nodeCount = triggerPool.Count;
+ var totalTriggers = _entityTable.ListSpawns(ent.Comp.TriggersTable)
+ .Count();
+ nodeCount = int.Min(nodeCount, totalTriggers);
+ var triggerPoolData = new TriggerPoolData(nodeCount);
+
ResizeNodeGraph(ent, nodeCount);
while (nodeCount > 0)
{
- GenerateArtifactSegment(ent, triggerPool, ref nodeCount);
+ GenerateArtifactSegment(ent, triggerPoolData, ref nodeCount);
}
RebuildXenoArtifactMetaData((ent, ent));
}
- ///
- /// Creates pool from all node triggers that current artifact can support.
- /// As artifact cannot re-use triggers, pool will be growing smaller
- /// and smaller with each node generated.
- ///
- /// Artifact for which pool should be created.
- ///
- /// Max size of pool. Resulting pool is not guaranteed to be exactly as large, but it will 100% won't be bigger.
- ///
- private List CreateTriggerPool(Entity ent, int size)
- {
- var triggerPool = new List(size);
- var weightsProto = ProtoMan.Index(ent.Comp.TriggerWeights);
- var weightsByTriggersLeft = new Dictionary, float>(weightsProto.Weights);
-
- while (triggerPool.Count < size)
- {
- // OOPS! We ran out of triggers.
- if (weightsByTriggersLeft.Count == 0)
- {
- Log.Error($"Insufficient triggers for generating {ToPrettyString(ent)}! Needed {size} but had {triggerPool.Count}");
- return triggerPool;
- }
-
- var triggerId = RobustRandom.PickAndTake(weightsByTriggersLeft);
- var trigger = ProtoMan.Index(triggerId);
- if (_entityWhitelist.IsWhitelistFail(trigger.Whitelist, ent))
- continue;
-
- triggerPool.Add(trigger);
- }
-
- return triggerPool;
- }
-
///
/// Generates segment of artifact - isolated graph, nodes inside which are interconnected.
/// As size of segment is randomized - it is subtracted from node count.
///
private void GenerateArtifactSegment(
Entity ent,
- List triggerPool,
+ TriggerPoolData triggerPoolData,
ref int nodeCount
)
{
var segmentSize = GetArtifactSegmentSize(ent, nodeCount);
nodeCount -= segmentSize;
- var populatedNodes = PopulateArtifactSegmentRecursive(ent, triggerPool, ref segmentSize);
+ var populatedNodes = PopulateArtifactSegmentRecursive(ent, triggerPoolData, ref segmentSize);
var segments = GetSegmentsFromNodes(ent, populatedNodes).ToList();
@@ -139,7 +112,7 @@ public sealed partial class XenoArtifactSystem
///
private List> PopulateArtifactSegmentRecursive(
Entity ent,
- List triggerPool,
+ TriggerPoolData triggerPoolData,
ref int segmentSize,
int iteration = 0
)
@@ -162,13 +135,25 @@ public sealed partial class XenoArtifactSystem
var nodes = new List>();
for (var i = 0; i < nodeCount; i++)
{
- var trigger = RobustRandom.PickAndTake(triggerPool);
- nodes.Add(CreateNode(ent, trigger, iteration));
+ var trigger = _entityTable.GetFirstOrDefault(ent.Comp.TriggersTable, ctx: triggerPoolData.Context);
+ if (trigger == null)
+ {
+ trigger = DummyTrigger;
+ Log.Error(
+ "Failed to generate proper artifact - selector {selector} with excepted entities {excepted} "
+ + "provided zero triggers upon requesting new one",
+ ent.Comp.TriggersTable,
+ string.Join(", ", triggerPoolData.UsedTriggers.Select(x => x.Id))
+ );
+ }
+
+ triggerPoolData.AddTriggerAsUsed(trigger.Value);
+ nodes.Add(CreateNode(ent, trigger.Value, iteration));
}
var successors = PopulateArtifactSegmentRecursive(
ent,
- triggerPool,
+ triggerPoolData,
ref segmentSize,
iteration: iteration + 1
);
@@ -216,4 +201,31 @@ public sealed partial class XenoArtifactSystem
return segmentSize;
}
+
+ ///
+ /// Container that represents pool of XenoArtifact triggers.
+ ///
+ private sealed class TriggerPoolData
+ {
+ private readonly HashSet _usedTriggers;
+
+ public TriggerPoolData(int requestedSize)
+ {
+ _usedTriggers = new(requestedSize);
+ Context = new EntityTableContext(new Dictionary
+ {
+ [ExcludeEntitiesFromContextCondition.EntitiesToExclude] = _usedTriggers
+ });
+ }
+
+ public readonly EntityTableContext Context;
+
+ public void AddTriggerAsUsed(EntProtoId trigger)
+ {
+ if (!_usedTriggers.Add(trigger))
+ throw new ArgumentException();
+ }
+
+ public IReadOnlyCollection UsedTriggers => _usedTriggers;
+ }
}
diff --git a/Content.Shared/EntityTable/Conditions/ExcludeEntitiesFromContextCondition.cs b/Content.Shared/EntityTable/Conditions/ExcludeEntitiesFromContextCondition.cs
index d7bdc9e59b..573293ac7a 100644
--- a/Content.Shared/EntityTable/Conditions/ExcludeEntitiesFromContextCondition.cs
+++ b/Content.Shared/EntityTable/Conditions/ExcludeEntitiesFromContextCondition.cs
@@ -11,6 +11,7 @@ public sealed partial class ExcludeEntitiesFromContextCondition : EntityTableCon
{
///
/// Context key used to track which entity prototypes should not be spawned.
+ /// Value should be .
///
public const string EntitiesToExclude = "EntitiesToExclude";
diff --git a/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs b/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs
index 66c52155cc..f209ef956f 100644
--- a/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs
@@ -45,4 +45,10 @@ public sealed partial class AllSelector : EntityTableSelectorWithChildrenBase
}
}
}
+
+ ///
+ public override string ToString()
+ {
+ return $"All({string.Join(", ", Children)})";
+ }
}
diff --git a/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs b/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs
index bc99f2cf83..4eec6320d2 100644
--- a/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs
@@ -44,4 +44,10 @@ public sealed partial class EntSelector : EntityTableSelector
{
yield return (Id, Amount.Average());
}
+
+ ///
+ public override string ToString()
+ {
+ return $"{Id} x{Amount.Average()}";
+ }
}
diff --git a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs
index 33cca7bd90..4aa6206095 100644
--- a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs
@@ -65,4 +65,10 @@ public sealed partial class GroupSelector : EntityTableSelectorWithChildrenBase
}
}
}
+
+ ///
+ public override string ToString()
+ {
+ return $"Group({string.Join(", ", Children.Select(x => $"{x}: {x.Weight}"))})";
+ }
}
diff --git a/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs b/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs
index 1ca91051af..5c1a4952cf 100644
--- a/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs
@@ -47,4 +47,10 @@ public sealed partial class NestedSelector : EntityTableSelectorWithNestedBase
{
return proto.Index(TableId).Table.AverageSpawns(entMan, proto, ctx);
}
+
+ ///
+ public override string ToString()
+ {
+ return $"Nested({TableId})";
+ }
}
diff --git a/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs b/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs
index 72ef181cbe..a24f74c816 100644
--- a/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs
@@ -25,4 +25,10 @@ public sealed partial class NoneSelector : EntityTableSelector
{
yield break;
}
+
+ ///
+ public override string ToString()
+ {
+ return "None";
+ }
}
diff --git a/Content.Shared/EntityTable/EntityTableSystem.cs b/Content.Shared/EntityTable/EntityTableSystem.cs
index e75748cb66..8241b33359 100644
--- a/Content.Shared/EntityTable/EntityTableSystem.cs
+++ b/Content.Shared/EntityTable/EntityTableSystem.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using Content.Shared.EntityTable.EntitySelectors;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
@@ -10,6 +11,30 @@ public sealed partial class EntityTableSystem : EntitySystem
{
[Dependency] private IRobustRandom _random = default!;
+ ///
+ /// Iterates once through Entities that EntitySelector in EntityTableProto provides and picks first one.
+ ///
+ public EntProtoId? GetFirstOrDefault(
+ EntityTablePrototype entTableProto,
+ IRobustRandom? rand = null,
+ EntityTableContext? ctx = null
+ )
+ {
+ return GetSpawns(entTableProto, rand, ctx).FirstOrDefault();
+ }
+
+ ///
+ /// Iterates once through Entities that EntitySelector provides and picks first one.
+ ///
+ public EntProtoId? GetFirstOrDefault(
+ EntityTableSelector? entTableProto,
+ IRobustRandom? rand = null,
+ EntityTableContext? ctx = null
+ )
+ {
+ return GetSpawns(entTableProto, rand, ctx).FirstOrDefault();
+ }
+
///
/// Compiles a random list of entity prototypes using constraints.
///
diff --git a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoEffectParser.cs b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactEffectParser.cs
similarity index 88%
rename from Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoEffectParser.cs
rename to Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactEffectParser.cs
index b01747e979..77f67b3e84 100644
--- a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoEffectParser.cs
+++ b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactEffectParser.cs
@@ -1,4 +1,3 @@
-using System.Linq;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
using Robust.Shared.Toolshed;
@@ -11,7 +10,7 @@ namespace Content.Shared.Toolshed.TypeParsers.XenoArtifact;
/// Custom type parser for toolshed commands
/// that lets choose entity prototype of XenoArtifact effect.
///
-public sealed partial class XenoEffectParser : CustomCompletionParser>
+public sealed partial class XenoArtifactEffectParser : CustomCompletionParser>
{
private static readonly ProtoId EffectCategoryId = "XenoArtifactEffects";
diff --git a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs
index 23266f7a5d..e8f15cb165 100644
--- a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs
+++ b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs
@@ -31,14 +31,18 @@ public sealed partial class XenoArtifactNodeParser : CustomCompletionParser<(Ent
node =>
{
var metadata = _entityManager.GetComponent(node);
- var entDescription = Loc.GetString(metadata.EntityDescription);
+ var effect = Loc.GetString(metadata.EntityDescription);
+ var trigger = node.Comp.TriggerTip.HasValue
+ ? Loc.GetString(node.Comp.TriggerTip)
+ : "Unknown";
return new CompletionOption(
node.Owner.ToString(),
Loc.GetString(
"command-xenoartifact-common-node-hint",
("depth", node.Comp.Depth),
("nodeId", artifact.GetNodeId(node.Owner)),
- ("nodeDetail", entDescription)
+ ("trigger", trigger),
+ ("effect", effect)
)
);
});
diff --git a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactTriggerParser.cs b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactTriggerParser.cs
new file mode 100644
index 0000000000..1ebae9118c
--- /dev/null
+++ b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactTriggerParser.cs
@@ -0,0 +1,26 @@
+using Robust.Shared.Console;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Toolshed;
+using Robust.Shared.Toolshed.Syntax;
+using Robust.Shared.Toolshed.TypeParsers;
+
+namespace Content.Shared.Toolshed.TypeParsers.XenoArtifact;
+
+///
+/// Custom type parser for toolshed commands
+/// that lets choose entity prototype of XenoArtifact trigger.
+///
+public sealed partial class XenoArtifactTriggerParser : CustomCompletionParser>
+{
+ private static readonly ProtoId TriggerCategoryId = "XenoArtifactTriggers";
+
+ [Dependency] private IPrototypeManager _prototype = default!;
+
+ public override CompletionResult TryAutocomplete(ParserContext ctx, CommandArgument? arg)
+ {
+ var hint = ToolshedCommand.GetArgHint(arg, typeof(ProtoId));
+ var completionOptions = CompletionHelper.EntityPrototypes(ctx.GetWord(), TriggerCategoryId, _prototype);
+ return CompletionResult.FromHintOptions(completionOptions, hint);
+
+ }
+}
diff --git a/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactComponent.cs b/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactComponent.cs
index 144dccc546..9c87b80a2a 100644
--- a/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactComponent.cs
+++ b/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactComponent.cs
@@ -2,7 +2,6 @@ using Content.Shared.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Destructible.Thresholds;
using Content.Shared.EntityTable.EntitySelectors;
-using Content.Shared.Xenoarchaeology.Artifact.Prototypes;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
@@ -146,7 +145,10 @@ public sealed partial class XenoArtifactComponent : Component
/// Triggers that can be used during this artefact generation.
///
[DataField]
- public ProtoId TriggerWeights = "DefaultTriggers";
+ public EntityTableSelector TriggersTable = new NestedSelector
+ {
+ TableId = "XenoArtifactTriggerDefaultTable"
+ };
#endregion
///
diff --git a/Content.Shared/Xenoarchaeology/Artifact/Prototypes/XenoArchTriggerPrototype.cs b/Content.Shared/Xenoarchaeology/Artifact/Prototypes/XenoArchTriggerPrototype.cs
deleted file mode 100644
index 05a33ea037..0000000000
--- a/Content.Shared/Xenoarchaeology/Artifact/Prototypes/XenoArchTriggerPrototype.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using Content.Shared.Random;
-using Content.Shared.Whitelist;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.Xenoarchaeology.Artifact.Prototypes;
-
-/// Proto for xeno artifact triggers - markers, which event could trigger node to unlock it.
-[Prototype]
-public sealed partial class XenoArchTriggerPrototype : IPrototype
-{
- ///
- [IdDataField]
- public string ID { get; private set; } = default!;
-
- ///
- /// Tip for user on how to activate this trigger.
- ///
- [DataField]
- public LocId Tip;
-
- ///
- /// Whitelist, describing for which subtype of artifacts this trigger could be used.
- ///
- [DataField]
- public EntityWhitelist? Whitelist;
-
- ///
- /// List of components that represent ways to trigger node.
- ///
- [DataField]
- public ComponentRegistry Components = new();
-}
-
-///
-/// Container for list of xeno artifact triggers and their respective weights to be used in case randomly rolling trigger is required.
-///
-[Prototype]
-public sealed partial class WeightedRandomXenoArchTriggerPrototype : IWeightedRandomPrototype
-{
- [IdDataField]
- public string ID { get; private set; } = default!;
-
- [DataField]
- public Dictionary, float> Weights { get; private set; } = new();
-}
diff --git a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs
index cf63b0ec84..7a182599e6 100644
--- a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs
+++ b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs
@@ -2,7 +2,6 @@ using System.Linq;
using Content.Shared.EntityTable;
using Content.Shared.NameIdentifier;
using Content.Shared.Xenoarchaeology.Artifact.Components;
-using Content.Shared.Xenoarchaeology.Artifact.Prototypes;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
@@ -81,7 +80,7 @@ public abstract partial class SharedXenoArtifactSystem
///
/// Creates artifact node entity, attaching trigger and marking depth level for future use.
///
- public Entity CreateNode(Entity ent, ProtoId trigger, int depth = 0)
+ public Entity CreateNode(Entity ent, EntProtoId trigger, int depth = 0)
{
var triggerProto = ProtoMan.Index(trigger);
return CreateNode(ent, triggerProto, depth);
@@ -90,7 +89,7 @@ public abstract partial class SharedXenoArtifactSystem
///
/// Creates artifact node entity, attaching trigger and marking depth level for future use.
///
- public Entity CreateNode(Entity ent, XenoArchTriggerPrototype trigger, int depth = 0)
+ public Entity CreateNode(Entity ent, EntityPrototype trigger, int depth = 0)
{
var entProtoId = _entityTable.GetSpawns(ent.Comp.EffectsTable)
.First();
@@ -100,14 +99,15 @@ public abstract partial class SharedXenoArtifactSystem
///
/// Creates artifact node entity, attaching trigger and marking depth level for future use.
///
- public Entity CreateNode(Entity ent, EntProtoId effect, XenoArchTriggerPrototype trigger, int depth = 0)
+ public Entity CreateNode(Entity ent, EntProtoId effect, EntityPrototype trigger, int depth = 0)
{
AddNode((ent, ent), effect, out var nodeEnt, dirty: false);
DebugTools.Assert(nodeEnt.HasValue, "Failed to create node on artifact.");
var nodeComponent = nodeEnt.Value.Comp;
nodeComponent.Depth = depth;
- nodeComponent.TriggerTip = trigger.Tip;
+ nodeComponent.TriggerTip = trigger.Name;
+
EntityManager.AddComponents(nodeEnt.Value, trigger.Components);
Dirty(nodeEnt.Value);
diff --git a/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl b/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl
index e65443defd..2aa21f8efd 100644
--- a/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl
+++ b/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl
@@ -26,4 +26,4 @@ command-spawnartifactwithnode-spawn-artifact-item-hint = use hand-held artifact
command-spawnartifactwithnode-spawn-artifact-structure-hint = use structure-like stationary artifact
command-spawnartifactwithnode-spawn-artifact-type-hint =
-command-xenoartifact-common-node-hint = depth {$depth} node {$nodeId} trigger {$nodeDetail}
+command-xenoartifact-common-node-hint = depth {$depth} node {$nodeId} trigger: '{$trigger}', effect: '{$effect}'
diff --git a/Resources/Locale/en-US/entity-categories.ftl b/Resources/Locale/en-US/entity-categories.ftl
index 3ed481333e..157115ac6d 100644
--- a/Resources/Locale/en-US/entity-categories.ftl
+++ b/Resources/Locale/en-US/entity-categories.ftl
@@ -6,5 +6,6 @@ entity-category-name-mapping = Mapping
entity-category-name-donotmap = Do not map
entity-category-name-status-effects = Status Effects
entity-category-name-xeno-artifact-effects = Xeno Artifact Effects
+entity-category-name-xeno-artifact-triggers = Xeno Artifact triggers
entity-category-suffix-donotmap = DO NOT MAP
diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl
index bfffcde8cb..bc9df24f4d 100644
--- a/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl
+++ b/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl
@@ -22,65 +22,6 @@ artifact-effect-hint-polymorph = Transmogrificational activity
artifact-effect-hint-magnet = Magnetic waves
artifact-effect-hint-visual = Visual distortions
-# the triggers should be more obvious than the effects
-# gives people an idea of what to do: don't be too specific (i.e. no "welders")
-
-artifact-trigger-hint-electricity = Electricity
-artifact-trigger-hint-heat = High temperatures
-artifact-trigger-hint-physical = Physical trauma
-artifact-trigger-hint-tool = Tool usage
-artifact-trigger-hint-music = Sonic vibrations
-artifact-trigger-hint-water = Hydro-reactive
-artifact-trigger-hint-blood = Reaction with hematological fluid
-artifact-trigger-hint-magnet = Magnetic waves
-artifact-trigger-hint-death = Life essence
-artifact-trigger-hint-radiation = Radiation
-artifact-trigger-hint-pressure = Extreme pressure
-artifact-trigger-hint-regular-gases = Standard atmospheric gases
-artifact-trigger-hint-plasma = Gaseous plasma
-artifact-trigger-hint-land = Active deceleration
-artifact-trigger-hint-examine = Examination
-artifact-trigger-hint-medical = Therapeutic chemicals
-
-xenoarch-trigger-tip-music = Harmonical sound vibrations
-xenoarch-trigger-tip-heat = High temperature gas
-xenoarch-trigger-tip-cold = Low temperature gas
-xenoarch-trigger-tip-no-oxygen = Oxygen-free environment
-xenoarch-trigger-tip-water = Water
-xenoarch-trigger-tip-co2 = Carbon dioxide
-xenoarch-trigger-tip-plasma = Non-solid plasma
-xenoarch-trigger-tip-tritium = Tritium
-xenoarch-trigger-tip-ammonia = Ammonia
-xenoarch-trigger-tip-n2o = Nitrous oxide
-xenoarch-trigger-tip-frezon = Frezon
-xenoarch-trigger-tip-radiation = Heavy-ion radiation
-xenoarch-trigger-tip-microwave = Microwave radiation
-xenoarch-trigger-tip-brute-damage = Physical damage
-xenoarch-trigger-tip-interaction = Physical interaction
-xenoarch-trigger-tip-wrenching = Tightening
-xenoarch-trigger-tip-prying = Prying
-xenoarch-trigger-tip-screwing = Screwing
-xenoarch-trigger-tip-pulsing = Pulsing
-xenoarch-trigger-tip-pressure-low = Low pressure
-xenoarch-trigger-tip-pressure-high = High pressure
-xenoarch-trigger-tip-examine = Close inspection
-xenoarch-trigger-tip-timer = Regular self-activation
-xenoarch-trigger-tip-blood = Blood
-xenoarch-trigger-tip-throw = Being thrown
-xenoarch-trigger-tip-death = Death
-xenoarch-trigger-tip-magnet = Magnetic waves
-xenoarch-trigger-tip-money = Bribery
-xenoarch-trigger-tip-knowledge = Knowledge Intake
-xenoarch-trigger-tip-carbs = Carbohydrate Intake
-xenoarch-trigger-tip-meat = Protein Intake
-xenoarch-trigger-tip-produce = Healthy Produce Intake
-xenoarch-trigger-tip-stamp = Bureaucratic Approval
-xenoarch-trigger-tip-shock = Electrical Shock
-xenoarch-trigger-tip-particle = Singularity-Effecting Particles
-xenoarch-trigger-tip-anomparticle = Anomaly-Effecting Particles
-xenoarch-trigger-tip-stamina-damage = Organic Exhaustion
-xenoarch-trigger-tip-laser = High-Intensity photon impacts
-
### Description hints
xenoarch-trigger-examine-wrenching = There's a loose bit spinning around.
xenoarch-trigger-examine-prying = There's a panel coming up from the surface.
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml
index ea6a16482c..446dc3302f 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml
@@ -52,6 +52,8 @@
graph: Artifact
node: done
- type: XenoArtifact
+ triggersTable: !type:NestedSelector
+ tableId: XenoArtifactHandheldOnlyTriggerTable
effectsTable: !type:GroupSelector
children:
- !type:NestedSelector
diff --git a/Resources/Prototypes/Entities/categories.yml b/Resources/Prototypes/Entities/categories.yml
index 4fb30f9ef0..e2928e2185 100644
--- a/Resources/Prototypes/Entities/categories.yml
+++ b/Resources/Prototypes/Entities/categories.yml
@@ -37,3 +37,8 @@
id: XenoArtifactEffects
name: entity-category-name-xeno-artifact-effects
hideSpawnMenu: true
+
+- type: entityCategory
+ id: XenoArtifactTriggers
+ name: entity-category-name-xeno-artifact-triggers
+ hideSpawnMenu: true
diff --git a/Resources/Prototypes/XenoArch/triggers.yml b/Resources/Prototypes/XenoArch/triggers.yml
index 75fcbba673..7cc71669dd 100644
--- a/Resources/Prototypes/XenoArch/triggers.yml
+++ b/Resources/Prototypes/XenoArch/triggers.yml
@@ -1,55 +1,100 @@
-- type: weightedRandomXenoArchTrigger
- id: DefaultTriggers
- weights:
- TriggerMusic: 1
- TriggerHeat: 1
- TriggerCold: 0.5
- TriggerNoOxygen: 1
- TriggerWater: 1
- TriggerCO2: 0.5
- TriggerPlasma: 0.5
- TriggerN2O: 0.5
- TriggerTritium: 0.1
- TriggerAmmonia: 0.1
- TriggerFrezon: 0.1
- TriggerRadiation: 1
- TriggerPressureHigh: 0.5
- TriggerPressureLow: 1
- TriggerExamine: 1
- TriggerBruteDamage: 1
- #TriggerInteraction: 1 #this one interferes with activating artifact AND brute dmg!
- TriggerWrenching: 0.5
- TriggerPrying: 0.5
- TriggerScrewing: 0.5
- TriggerPulsing: 0.5
- TriggerTimer: 0.25
- TriggerBlood: 1
- TriggerThrow: 1
- TriggerDeath: 1
- TriggerMagnet: 1
- TriggerConsumeMoney: 1
- TriggerConsumeKnowledge: 0.25
- TriggerConsumeCarbs: 1
- TriggerConsumeMeat: 0.5
- TriggerConsumeProduce: 0.5
- TriggerInteractStamp: 1
- TriggerInteractShock: 1
- TriggerAttackParticleEngine: 0.1
- TriggerAttackParticleAnomaly: 1
- TriggerAttackStaminaDamage: 1
- TriggerAttackLaser: 0.5
+- type: entityTable
+ id: XenoArtifactTriggerDefaultTable
+ table: !type:GroupSelector
+ conditionsForChildren:
+ - !type:ExcludeEntitiesFromContextCondition
+ children:
+ - id: TriggerMusic
+ - id: TriggerHeat
+ - id: TriggerCold
+ weight: 0.5
+ - id: TriggerNoOxygen
+ - id: TriggerWater
+ - id: TriggerCO2
+ weight: 0.5
+ - id: TriggerPlasma
+ weight: 0.5
+ - id: TriggerN2O
+ weight: 0.5
+ - id: TriggerTritium
+ weight: 0.1
+ - id: TriggerAmmonia
+ weight: 0.1
+ - id: TriggerFrezon
+ weight: 0.1
+ - id: TriggerRadiation
+ - id: TriggerPressureHigh
+ weight: 0.5
+ - id: TriggerPressureLow
+ - id: TriggerExamine
+ - id: TriggerBruteDamage
+ #- id: TriggerInteraction #this one interferes with activating artifact AND brute dmg!
+ - id: TriggerWrenching
+ weight: 0.5
+ - id: TriggerPrying
+ weight: 0.5
+ - id: TriggerScrewing
+ weight: 0.5
+ - id: TriggerPulsing
+ weight: 0.5
+ - id: TriggerTimer
+ weight: 0.25
+ - id: TriggerBlood
+ - id: TriggerDeath
+ - id: TriggerMagnet
+ - id: TriggerConsumeMoney
+ - id: TriggerConsumeKnowledge
+ weight: 0.25
+ - id: TriggerConsumeCarbs
+ - id: TriggerConsumeMeat
+ weight: 0.5
+ - id: TriggerConsumeProduce
+ weight: 0.5
+ - id: TriggerInteractStamp
+ - id: TriggerInteractShock
+ - id: TriggerAttackParticleAnomaly
+ - id: TriggerAttackStaminaDamage
+ - id: TriggerAttackLaser
+ weight: 0.5
+ - id: TriggerAttackParticleEngine
+ weight: 0.1
-- type: xenoArchTrigger
+- type: entityTable
+ id: XenoArtifactHandheldOnlyTriggerTable
+ table: !type:GroupSelector
+ conditionsForChildren:
+ - !type:ExcludeEntitiesFromContextCondition
+ children:
+ - !type:NestedSelector
+ tableId: XenoArtifactTriggerDefaultTable
+ weight: 35
+ - !type:GroupSelector # Handheld exclusive
+ weight: 2
+ children:
+ - id: TriggerThrow
+ - id: TriggerMicrowave
+
+- type: entity
+ abstract: true
+ id: BaseXenoArtifactTrigger
+ name: Unknown
+ categories: [XenoArtifactTriggers]
+
+#region Standard triggers
+
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerMusic
- tip: xenoarch-trigger-tip-music
+ name: Harmonical sound vibrations
components:
- type: XATCompNearby
requireComponentWithName: ActiveInstrument
radius: 2
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerHeat
- tip: xenoarch-trigger-tip-heat
+ name: High temperature gas
components:
- type: XATTemperature
targetTemperature: 373
@@ -57,15 +102,16 @@
- type: XATDamageThresholdReached
typesNeeded:
Heat: 20
-# This kinda trivializes the difficulty.
-# - type: XATToolUse
-# requiredTool: Welding
-# delay: 5
-# fuel: 10
+ # This kinda trivializes the difficulty.
+ # - type: XATToolUse
+ # requiredTool: Welding
+ # delay: 5
+ # fuel: 10
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerCold
- tip: xenoarch-trigger-tip-cold
+ name: Low temperature gas
components:
- type: XATTemperature
targetTemperature: 255
@@ -74,18 +120,20 @@
typesNeeded:
Cold: 20
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerNoOxygen
- tip: xenoarch-trigger-tip-no-oxygen
+ name: Oxygen-free environment
components:
- type: XATGas
targetGas: Oxygen
moles: 10
shouldBePresent: false
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerWater
- tip: xenoarch-trigger-tip-water
+ name: Water
components:
- type: XATGas
targetGas: WaterVapor
@@ -93,9 +141,10 @@
reagents:
- Water
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerCO2
- tip: xenoarch-trigger-tip-co2
+ name: Carbon dioxide
components:
- type: XATGas
targetGas: CarbonDioxide
@@ -103,9 +152,10 @@
reagents:
- CarbonDioxide
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerPlasma
- tip: xenoarch-trigger-tip-plasma
+ name: Non-solid plasma
components:
- type: XATGas
targetGas: Plasma
@@ -113,9 +163,10 @@
reagents:
- Plasma
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerTritium
- tip: xenoarch-trigger-tip-tritium
+ name: Tritium
components:
- type: XATGas
targetGas: Tritium
@@ -123,9 +174,10 @@
reagents:
- Tritium
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerAmmonia
- tip: xenoarch-trigger-tip-ammonia
+ name: Ammonia
components:
- type: XATGas
targetGas: Ammonia
@@ -133,9 +185,10 @@
reagents:
- Ammonia
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerN2O
- tip: xenoarch-trigger-tip-n2o
+ name: Nitrous oxide
components:
- type: XATGas
targetGas: NitrousOxide
@@ -143,9 +196,10 @@
reagents:
- NitrousOxide
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerFrezon
- tip: xenoarch-trigger-tip-frezon
+ name: Frezon
components:
- type: XATGas
targetGas: Frezon
@@ -153,105 +207,108 @@
reagents:
- Frezon
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerRadiation
- tip: xenoarch-trigger-tip-radiation
+ name: Heavy-ion radiation
components:
- type: XATDamageThresholdReached
typesNeeded:
Radiation: 20
-- type: xenoArchTrigger
- id: TriggerMicrowave
- tip: xenoarch-trigger-tip-microwave
- whitelist:
- components:
- - Item
- components:
- - type: XATMicrowave
-
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerPressureHigh
- tip: xenoarch-trigger-tip-pressure-high
+ name: High pressure
components:
- type: XATPressure
maxPressureThreshold: 385
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerPressureLow
- tip: xenoarch-trigger-tip-pressure-low
+ name: Low pressure
components:
- type: XATPressure
minPressureThreshold: 50
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerExamine
- tip: xenoarch-trigger-tip-examine
+ name: Close inspection
components:
- type: XATExamine
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerBruteDamage
- tip: xenoarch-trigger-tip-brute-damage
+ name: Physical damage
components:
- type: XATDamageThresholdReached
groupsNeeded:
Brute: 20
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerInteraction
- tip: xenoarch-trigger-tip-interaction
+ name: Physical interaction
components:
- type: XATInteraction
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerWrenching
- tip: xenoarch-trigger-tip-wrenching
+ name: Tightening
components:
- type: XATToolUse
requiredTool: Anchoring
- type: XATExaminableText
examineText: xenoarch-trigger-examine-wrenching
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerPrying
- tip: xenoarch-trigger-tip-prying
+ name: Prying
components:
- type: XATToolUse
requiredTool: Prying
- type: XATExaminableText
examineText: xenoarch-trigger-examine-prying
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerScrewing
- tip: xenoarch-trigger-tip-screwing
+ name: Screwing
components:
- type: XATToolUse
requiredTool: Screwing
- type: XATExaminableText
examineText: xenoarch-trigger-examine-screwing
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerPulsing
- tip: xenoarch-trigger-tip-pulsing
+ name: Pulsing
components:
- type: XATToolUse
requiredTool: Pulsing
- type: XATExaminableText
examineText: xenoarch-trigger-examine-pulsing
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerTimer
- tip: xenoarch-trigger-tip-timer
+ name: Regular self-activation
components:
- type: XATTimer
possibleDelayInSeconds:
min: 80
max: 120
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerBlood
- tip: xenoarch-trigger-tip-blood
+ name: Blood
components:
- type: XATReactive
reagents:
@@ -264,30 +321,24 @@
- Sap
- SulfurBlood
-- type: xenoArchTrigger
- id: TriggerThrow
- tip: xenoarch-trigger-tip-throw
- whitelist:
- components:
- - Item
- components:
- - type: XATItemLand
-
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerDeath
- tip: xenoarch-trigger-tip-death
+ name: Death
components:
- type: XATDeath
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerMagnet
- tip: xenoarch-trigger-tip-magnet
+ name: Magnetic waves
components:
- type: XATMagnet
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerConsumeMoney
- tip: xenoarch-trigger-tip-money
+ name: Bribery
components:
- type: XATInteractWith
interactionCount:
@@ -300,9 +351,10 @@
components:
- Cash
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerConsumeKnowledge
- tip: xenoarch-trigger-tip-knowledge
+ name: Knowledge intake
components:
- type: XATInteractWith
destroyAfter: true
@@ -314,9 +366,10 @@
tags:
- Book
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerConsumeCarbs
- tip: xenoarch-trigger-tip-carbs
+ name: Carbohydrate intake
components:
- type: XATInteractWith
destroyAfter: true
@@ -334,9 +387,10 @@
- Pie
- Pizza
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerConsumeMeat
- tip: xenoarch-trigger-tip-meat
+ name: Protein intake
components:
- type: XATInteractWith
destroyAfter: true
@@ -353,9 +407,10 @@
- Protein
- UncookedAnimalProteins
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerConsumeProduce
- tip: xenoarch-trigger-tip-produce
+ name: Healthy produce intake
components:
- type: XATInteractWith
destroyAfter: true
@@ -372,9 +427,10 @@
- Ambrosia
- Mushroom
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerInteractStamp
- tip: xenoarch-trigger-tip-stamp
+ name: Bureaucratic approval
components:
- type: XATInteractWith
interactionTime: 0.5
@@ -387,43 +443,48 @@
components:
- Stamp
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerInteractShock
- tip: xenoarch-trigger-tip-shock
+ name: Electrical shock
components:
- type: XATShock
- type: XATDamageThresholdReached
typesNeeded:
Shock: 5
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerAttackParticleEngine
- tip: xenoarch-trigger-tip-particle
+ name: Singularity-Effecting particles
components:
- type: XATInteractAttack
whitelist:
components:
- ParticleProjectile
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerAttackParticleAnomaly
- tip: xenoarch-trigger-tip-anomparticle
+ name: Anomaly-Effecting particles
components:
- type: XATInteractAttack
whitelist:
components:
- AnomalousParticle
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerAttackStaminaDamage
- tip: xenoarch-trigger-tip-stamina-damage
+ name: Organic exhaustion
components:
- type: XATStaminaDamageThresholdReached
damageNeeded: 8 # half a practice disabler capacity
-- type: xenoArchTrigger
+- type: entity
+ parent: BaseXenoArtifactTrigger
id: TriggerAttackLaser
- tip: xenoarch-trigger-tip-laser
+ name: High-Intensity photon impacts
components:
- type: XATInteractAttack
interactionCount:
@@ -433,3 +494,22 @@
- LaserProjectile
tags:
- EmitterBolt
+
+#endregion
+#region Handheld triggers
+
+- type: entity
+ parent: BaseXenoArtifactTrigger
+ id: TriggerMicrowave
+ name: Microwave radiation
+ components:
+ - type: XATMicrowave
+
+- type: entity
+ parent: BaseXenoArtifactTrigger
+ id: TriggerThrow
+ name: Being thrown
+ components:
+ - type: XATItemLand
+
+#endregion