Feature/refactor xenoarch trigger to be entity table ed (#45608)

* refactor: rough strokes for initial implementation

* refactor: fix ada remarks

* refactor: fix XenoArtifactNodeParser not displaying trigger and effect properly in autocompletion

* refactor: more changes for IsNotRepeatingCondition

* refactor: update triggers declarations

* refactor: remove IsNotRepeatingCondition - duplicate

* refactor: fixup after merge with master

* refactor: properly handle creation of improper trigger set, all selectors gt ToString override!

* refactor: fix missing weight for some triggers, XenoArtifactCommand.UnlockAllNodes now accepts multiple entries

* refactor: fix trigger hints loc being name explicitly and failing tests

* yaml changes

* rename

* refactor: fix xml-doc copy-paste for XenoArtifactTriggerParser

---------

Co-authored-by: iaada <iaada@users.noreply.github.com>
This commit is contained in:
Fildrance 2026-08-31 20:58:52 +00:00 • committed by GitHub
parent 9c8df525bc
commit 8bf0961e5a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 399 additions and 314 deletions

View file

@ -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
/// <summary> Unlocks all nodes of artifact. </summary>
[CommandImplementation("unlockallnodes")]
public void UnlockAllNodes([PipedArgument] EntityUid artifactEntityUid)
public void UnlockAllNodes([PipedArgument] IEnumerable<EntityUid> artifactUids)
{
_artifact ??= Sys<XenoArtifactSystem>();
var comp = Comp<XenoArtifactComponent>(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<XenoArtifactComponent>(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<XenoArtifactComponent> artifact,
[CommandArgument(typeof(XenoEffectParser))] ProtoId<EntityPrototype> effect,
[CommandArgument] ProtoId<XenoArchTriggerPrototype> trigger
[CommandArgument(typeof(XenoArtifactEffectParser))] ProtoId<EntityPrototype> effect,
[CommandArgument(typeof(XenoArtifactTriggerParser))] ProtoId<EntityPrototype> trigger
)
{
CreateNode(artifact, effect, trigger);
@ -145,8 +147,8 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
[CommandImplementation("createnodeatdepth")]
public void CreateNodeAtDepth(
[CommandArgument(typeof(XenoArtifactNodeParser))] (Entity<XenoArtifactComponent> Artifact, Entity<XenoArtifactNodeComponent> Node) tuple,
[CommandArgument(typeof(XenoEffectParser))] ProtoId<EntityPrototype> effect,
[CommandArgument] ProtoId<XenoArchTriggerPrototype> trigger
[CommandArgument(typeof(XenoArtifactEffectParser))] ProtoId<EntityPrototype> effect,
[CommandArgument(typeof(XenoArtifactTriggerParser))] ProtoId<EntityPrototype> 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<EntityPrototype> artifactType,
[CommandArgument(typeof(XenoEffectParser))] ProtoId<EntityPrototype> effect,
[CommandArgument] ProtoId<XenoArchTriggerPrototype> trigger
[CommandArgument(typeof(XenoArtifactEffectParser))] ProtoId<EntityPrototype> effect,
[CommandArgument(typeof(XenoArtifactTriggerParser))] ProtoId<EntityPrototype> trigger
)
{
if (target.AttachedEntity == null)
@ -215,7 +217,7 @@ public sealed partial class XenoArtifactCommand : ToolshedCommand
private void CreateNode(
Entity<XenoArtifactComponent> artifact,
ProtoId<EntityPrototype> effect,
ProtoId<XenoArchTriggerPrototype> trigger,
ProtoId<EntityPrototype> trigger,
Entity<XenoArtifactNodeComponent>? node = null
)
{

View file

@ -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!;
/// <summary>
/// Trigger for fallback scenario, when artifact acquired no trigger when generating artifact.
/// </summary>
private static readonly EntProtoId DummyTrigger = "TriggerExamine";
private void GenerateArtifactStructure(Entity<XenoArtifactComponent> 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));
}
/// <summary>
/// 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.
/// </summary>
/// <param name="ent">Artifact for which pool should be created.</param>
/// <param name="size">
/// Max size of pool. Resulting pool is not guaranteed to be exactly as large, but it will 100% won't be bigger.
/// </param>
private List<XenoArchTriggerPrototype> CreateTriggerPool(Entity<XenoArtifactComponent> ent, int size)
{
var triggerPool = new List<XenoArchTriggerPrototype>(size);
var weightsProto = ProtoMan.Index(ent.Comp.TriggerWeights);
var weightsByTriggersLeft = new Dictionary<ProtoId<XenoArchTriggerPrototype>, 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;
}
/// <summary>
/// Generates segment of artifact - isolated graph, nodes inside which are interconnected.
/// As size of segment is randomized - it is subtracted from node count.
/// </summary>
private void GenerateArtifactSegment(
Entity<XenoArtifactComponent> ent,
List<XenoArchTriggerPrototype> 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
/// </summary>
private List<Entity<XenoArtifactNodeComponent>> PopulateArtifactSegmentRecursive(
Entity<XenoArtifactComponent> ent,
List<XenoArchTriggerPrototype> triggerPool,
TriggerPoolData triggerPoolData,
ref int segmentSize,
int iteration = 0
)
@ -162,13 +135,25 @@ public sealed partial class XenoArtifactSystem
var nodes = new List<Entity<XenoArtifactNodeComponent>>();
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;
}
/// <summary>
/// Container that represents pool of XenoArtifact triggers.
/// </summary>
private sealed class TriggerPoolData
{
private readonly HashSet<EntProtoId> _usedTriggers;
public TriggerPoolData(int requestedSize)
{
_usedTriggers = new(requestedSize);
Context = new EntityTableContext(new Dictionary<string, object>
{
[ExcludeEntitiesFromContextCondition.EntitiesToExclude] = _usedTriggers
});
}
public readonly EntityTableContext Context;
public void AddTriggerAsUsed(EntProtoId trigger)
{
if (!_usedTriggers.Add(trigger))
throw new ArgumentException();
}
public IReadOnlyCollection<EntProtoId> UsedTriggers => _usedTriggers;
}
}

View file

@ -11,6 +11,7 @@ public sealed partial class ExcludeEntitiesFromContextCondition : EntityTableCon
{
/// <summary>
/// Context key used to track which entity prototypes should not be spawned.
/// Value should be <see cref="HashSet{EntityUid}"/>.
/// </summary>
public const string EntitiesToExclude = "EntitiesToExclude";

View file

@ -45,4 +45,10 @@ public sealed partial class AllSelector : EntityTableSelectorWithChildrenBase
}
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"All({string.Join(", ", Children)})";
}
}

View file

@ -44,4 +44,10 @@ public sealed partial class EntSelector : EntityTableSelector
{
yield return (Id, Amount.Average());
}
/// <inheritdoc/>
public override string ToString()
{
return $"{Id} x{Amount.Average()}";
}
}

View file

@ -65,4 +65,10 @@ public sealed partial class GroupSelector : EntityTableSelectorWithChildrenBase
}
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"Group({string.Join(", ", Children.Select(x => $"{x}: {x.Weight}"))})";
}
}

View file

@ -47,4 +47,10 @@ public sealed partial class NestedSelector : EntityTableSelectorWithNestedBase
{
return proto.Index(TableId).Table.AverageSpawns(entMan, proto, ctx);
}
/// <inheritdoc/>
public override string ToString()
{
return $"Nested({TableId})";
}
}

View file

@ -25,4 +25,10 @@ public sealed partial class NoneSelector : EntityTableSelector
{
yield break;
}
/// <inheritdoc/>
public override string ToString()
{
return "None";
}
}

View file

@ -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!;
/// <summary>
/// Iterates once through Entities that EntitySelector in EntityTableProto provides and picks first one.
/// </summary>
public EntProtoId? GetFirstOrDefault(
EntityTablePrototype entTableProto,
IRobustRandom? rand = null,
EntityTableContext? ctx = null
)
{
return GetSpawns(entTableProto, rand, ctx).FirstOrDefault();
}
/// <summary>
/// Iterates once through Entities that EntitySelector provides and picks first one.
/// </summary>
public EntProtoId? GetFirstOrDefault(
EntityTableSelector? entTableProto,
IRobustRandom? rand = null,
EntityTableContext? ctx = null
)
{
return GetSpawns(entTableProto, rand, ctx).FirstOrDefault();
}
/// <summary>
/// Compiles a random list of entity prototypes using constraints.
/// </summary>

View file

@ -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.
/// </summary>
public sealed partial class XenoEffectParser : CustomCompletionParser<ProtoId<EntityPrototype>>
public sealed partial class XenoArtifactEffectParser : CustomCompletionParser<ProtoId<EntityPrototype>>
{
private static readonly ProtoId<EntityCategoryPrototype> EffectCategoryId = "XenoArtifactEffects";

View file

@ -31,14 +31,18 @@ public sealed partial class XenoArtifactNodeParser : CustomCompletionParser<(Ent
node =>
{
var metadata = _entityManager.GetComponent<MetaDataComponent>(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)
)
);
});

View file

@ -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;
/// <summary>
/// Custom type parser for toolshed commands
/// that lets choose entity prototype of XenoArtifact trigger.
/// </summary>
public sealed partial class XenoArtifactTriggerParser : CustomCompletionParser<ProtoId<EntityPrototype>>
{
private static readonly ProtoId<EntityCategoryPrototype> TriggerCategoryId = "XenoArtifactTriggers";
[Dependency] private IPrototypeManager _prototype = default!;
public override CompletionResult TryAutocomplete(ParserContext ctx, CommandArgument? arg)
{
var hint = ToolshedCommand.GetArgHint(arg, typeof(ProtoId<EntityPrototype>));
var completionOptions = CompletionHelper.EntityPrototypes(ctx.GetWord(), TriggerCategoryId, _prototype);
return CompletionResult.FromHintOptions(completionOptions, hint);
}
}

View file

@ -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.
/// </summary>
[DataField]
public ProtoId<WeightedRandomXenoArchTriggerPrototype> TriggerWeights = "DefaultTriggers";
public EntityTableSelector TriggersTable = new NestedSelector
{
TableId = "XenoArtifactTriggerDefaultTable"
};
#endregion
/// <summary>

View file

@ -1,45 +0,0 @@
using Content.Shared.Random;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
namespace Content.Shared.Xenoarchaeology.Artifact.Prototypes;
/// <summary> Proto for xeno artifact triggers - markers, which event could trigger node to unlock it. </summary>
[Prototype]
public sealed partial class XenoArchTriggerPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// Tip for user on how to activate this trigger.
/// </summary>
[DataField]
public LocId Tip;
/// <summary>
/// Whitelist, describing for which subtype of artifacts this trigger could be used.
/// </summary>
[DataField]
public EntityWhitelist? Whitelist;
/// <summary>
/// List of components that represent ways to trigger node.
/// </summary>
[DataField]
public ComponentRegistry Components = new();
}
/// <summary>
/// Container for list of xeno artifact triggers and their respective weights to be used in case randomly rolling trigger is required.
/// </summary>
[Prototype]
public sealed partial class WeightedRandomXenoArchTriggerPrototype : IWeightedRandomPrototype<XenoArchTriggerPrototype>
{
[IdDataField]
public string ID { get; private set; } = default!;
[DataField]
public Dictionary<ProtoId<XenoArchTriggerPrototype>, float> Weights { get; private set; } = new();
}

View file

@ -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
/// <summary>
/// Creates artifact node entity, attaching trigger and marking depth level for future use.
/// </summary>
public Entity<XenoArtifactNodeComponent> CreateNode(Entity<XenoArtifactComponent> ent, ProtoId<XenoArchTriggerPrototype> trigger, int depth = 0)
public Entity<XenoArtifactNodeComponent> CreateNode(Entity<XenoArtifactComponent> 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
/// <summary>
/// Creates artifact node entity, attaching trigger and marking depth level for future use.
/// </summary>
public Entity<XenoArtifactNodeComponent> CreateNode(Entity<XenoArtifactComponent> ent, XenoArchTriggerPrototype trigger, int depth = 0)
public Entity<XenoArtifactNodeComponent> CreateNode(Entity<XenoArtifactComponent> ent, EntityPrototype trigger, int depth = 0)
{
var entProtoId = _entityTable.GetSpawns(ent.Comp.EffectsTable)
.First();
@ -100,14 +99,15 @@ public abstract partial class SharedXenoArtifactSystem
/// <summary>
/// Creates artifact node entity, attaching trigger and marking depth level for future use.
/// </summary>
public Entity<XenoArtifactNodeComponent> CreateNode(Entity<XenoArtifactComponent> ent, EntProtoId effect, XenoArchTriggerPrototype trigger, int depth = 0)
public Entity<XenoArtifactNodeComponent> CreateNode(Entity<XenoArtifactComponent> 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);

View file

@ -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 = <artifact entity proto id>
command-xenoartifact-common-node-hint = depth {$depth} node {$nodeId} trigger {$nodeDetail}
command-xenoartifact-common-node-hint = depth {$depth} node {$nodeId} trigger: '{$trigger}', effect: '{$effect}'

View file

@ -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

View file

@ -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.

View file

@ -52,6 +52,8 @@
graph: Artifact
node: done
- type: XenoArtifact
triggersTable: !type:NestedSelector
tableId: XenoArtifactHandheldOnlyTriggerTable
effectsTable: !type:GroupSelector
children:
- !type:NestedSelector

View file

@ -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

View file

@ -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