diff --git a/Content.Server/Commands/ContentCompletionHelper.cs b/Content.Server/Commands/ContentCompletionHelper.cs index bc80b28762..dbe200b9de 100644 --- a/Content.Server/Commands/ContentCompletionHelper.cs +++ b/Content.Server/Commands/ContentCompletionHelper.cs @@ -1,4 +1,4 @@ -using Content.Shared.Station.Components; +using Content.Shared.Station.Components; using Robust.Shared.Console; namespace Content.Server.Commands; diff --git a/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs b/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs index 4182bac081..c840978847 100644 --- a/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs +++ b/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs @@ -1,7 +1,7 @@ using Content.Server.Administration; -using Content.Server.Toolshed.TypeParsers.StatusEffects; using Content.Shared.Administration; using Content.Shared.StatusEffectNew; +using Content.Shared.Toolshed.TypeParsers; using Robust.Shared.Prototypes; using Robust.Shared.Toolshed; diff --git a/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs b/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs new file mode 100644 index 0000000000..169147de0c --- /dev/null +++ b/Content.Server/Toolshed/Commands/XenoArtifacts/XenoArtifactCommands.cs @@ -0,0 +1,242 @@ +using System.Text; +using Content.Server.Administration; +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; +using Robust.Shared.Toolshed; + +namespace Content.Server.Toolshed.Commands.XenoArtifacts; + +/// +/// Toolshed commands for manipulating xeno artifact. +/// +[ToolshedCommand, AdminCommand(AdminFlags.Debug)] +public sealed partial class XenoArtifactCommand : ToolshedCommand +{ + [Dependency] private IPrototypeManager _prototypeManager = default!; + + private XenoArtifactSystem? _artifact; + + public static readonly EntProtoId ArtifactPrototype = "ComplexXenoArtifactItem"; + + /// List existing artifacts. + [CommandImplementation("list")] + public IEnumerable List() + { + var query = EntityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _)) + { + yield return uid; + } + } + + /// + /// Output matrix of artifact nodes and how they are connected. + /// + [CommandImplementation("printmatrix")] + public string PrintMatrix([CommandArgument] Entity artifactEnt) + { + var nodeCount = artifactEnt.Comp.NodeVertices.Length; + + var sb = new StringBuilder("\n |"); + for (var i = 0; i < nodeCount; i++) + { + sb.Append($" {i:D2}|"); + } + + AddHorizontalFiller(sb); + + for (var i = 0; i < nodeCount; i++) + { + sb.Append($"\n{i:D2}|"); + for (var j = 0; j < nodeCount; j++) + { + var value = artifactEnt.Comp.NodeAdjacencyMatrix[i][j] + ? "X" + : " "; + sb.Append($" {value} |"); + } + AddHorizontalFiller(sb); + } + + return sb.ToString(); + + void AddHorizontalFiller(StringBuilder builder) + { + builder.AppendLine(); + builder.Append("--+"); + for (var i = 0; i < nodeCount; i++) + { + builder.Append("---+"); + } + } + } + + /// Output total research points artifact contains. + [CommandImplementation("totalresearch")] + public int TotalResearch([PipedArgument] EntityUid artifactEntityUid) + { + _artifact ??= Sys(); + var comp = Comp(artifactEntityUid); + + var sum = 0; + + var nodes = _artifact.GetAllNodes((artifactEntityUid, comp)); + foreach (var node in nodes) + { + sum += node.Comp.ResearchValue; + } + + return sum; + } + + /// + /// Spawns a bunch of artifacts and gets average total research points they can yield. + /// + [CommandImplementation("averageresearch")] + public float AverageResearch() + { + const int n = 100; + var sum = 0; + + for (var i = 0; i < n; i++) + { + var ent = Spawn(ArtifactPrototype, MapCoordinates.Nullspace); + sum += TotalResearch(ent); + Del(ent); + } + + return (float)sum / n; + } + + /// Unlocks all nodes of artifact. + [CommandImplementation("unlockallnodes")] + public void UnlockAllNodes([PipedArgument] EntityUid artifactEntityUid) + { + _artifact ??= Sys(); + var comp = Comp(artifactEntityUid); + + var nodes = _artifact.GetAllNodes((artifactEntityUid, comp)); + foreach (var node in nodes) + { + _artifact.SetNodeUnlocked((node, node.Comp)); + } + } + + /// + /// Create node in artifact (new on depth 0 or attach next to existing one). + /// + [CommandImplementation("createnode")] + public void CreateNodeNew( + [CommandArgument] Entity artifact, + [CommandArgument(typeof(XenoEffectParser))] ProtoId effect, + [CommandArgument] ProtoId trigger + ) + { + CreateNode(artifact, effect, trigger); + } + + /// Add a new node to the given artifact. + [CommandImplementation("createnodeatdepth")] + public void CreateNodeAtDepth( + [CommandArgument(typeof(XenoArtifactNodeParser))] (Entity Artifact, Entity Node) tuple, + [CommandArgument(typeof(XenoEffectParser))] ProtoId effect, + [CommandArgument] ProtoId trigger + ) + { + CreateNode(tuple.Artifact, effect, trigger, tuple.Node); + } + + /// Spawns a new xeno artifact with single node with the given trigger and effect. + [CommandImplementation("spawnartwithnode")] + public void SpawnArtifactWithNode( + [CommandArgument] ICommonSession target, + [CommandArgument(typeof(XenoArtifactTypeParser))] ProtoId artifactType, + [CommandArgument(typeof(XenoEffectParser))] ProtoId effect, + [CommandArgument] ProtoId trigger + ) + { + if (target.AttachedEntity == null) + return; + + var entity = EntityManager.SpawnNextToOrDrop(artifactType, target.AttachedEntity.Value); + if (!TryComp(entity, out XenoArtifactComponent? artifactComp)) + { + return; + } + + CreateNode((entity, artifactComp), effect, trigger); + } + + /// Marks a node as unlocked. + [CommandImplementation("unlocknode")] + public void UnlockNode( + [CommandArgument(typeof(XenoArtifactNodeParser))] + (Entity Artifact, Entity Node) tuple + ) + { + _artifact ??= Sys(); + _artifact.SetNodeUnlocked(tuple.Node.AsNullable()); + } + + /// Removes a node from a xeno artifact. + [CommandImplementation("removenode")] + public void RemoveNode( + [CommandArgument(typeof(XenoArtifactNodeParser))] + (Entity Artifact, Entity Node) tuple + ) + { + _artifact ??= Sys(); + _artifact.RemoveNode(tuple.Artifact.AsNullable(), tuple.Node.AsNullable()); + } + + /// Adds an edge between two nodes of a xeno artifact. + [CommandImplementation("addedge")] + public void AddEdge( + [CommandArgument(typeof(XenoArtifactNodeParser))] + (Entity Artifact, Entity Node) from, + [CommandArgument(typeof(XenoArtifactNodeParser))] + (Entity Artifact, Entity Node) to + ) + { + // no inter-artifact edges or self-connects allowed + if (from.Artifact.Owner != to.Artifact.Owner || from.Node.Owner == to.Node.Owner) + return; + + _artifact = Sys(); + _artifact.AddEdge(from.Artifact.AsNullable(), from.Node, to.Node); + } + + private void CreateNode( + Entity artifact, + ProtoId effect, + ProtoId trigger, + Entity? node = null + ) + { + var depth = 0; + if (node.HasValue) + { + depth = node.Value.Comp.Depth + 1; + } + + _artifact ??= Sys(); + if (!_prototypeManager.Resolve(trigger, out var triggerPrototype)) + return; + + var createdNode = _artifact.CreateNode(artifact, effect.Id, triggerPrototype, depth); + if (node.HasValue) + { + _artifact.AddEdge(artifact.AsNullable(), node.Value, createdNode); + } + else + { + _artifact.RebuildXenoArtifactMetaData(artifact.AsNullable()); + } + } +} diff --git a/Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs b/Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs deleted file mode 100644 index 839f7fa9ca..0000000000 --- a/Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.StatusEffectNew; -using Robust.Shared.Console; -using Robust.Shared.Prototypes; -using Robust.Shared.Toolshed; -using Robust.Shared.Toolshed.Syntax; -using Robust.Shared.Toolshed.TypeParsers; - -namespace Content.Server.Toolshed.TypeParsers.StatusEffects; - -public sealed class StatusEffectCompletionParser : CustomCompletionParser -{ - public override CompletionResult? TryAutocomplete(ParserContext ctx, CommandArgument? arg) - { - return CompletionResult.FromHintOptions(IoCManager.Resolve().System().StatusEffectPrototypes, GetArgHint(arg)); - } -} diff --git a/Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs b/Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs deleted file mode 100644 index 2671b814e3..0000000000 --- a/Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Content.Server.Administration; -using Content.Shared.Administration; -using Content.Shared.Xenoarchaeology.Artifact.Components; -using Robust.Shared.Console; - -namespace Content.Server.Xenoarchaeology.Artifact; - -/// Command for unlocking a specific node of a xeno artifact. -[AdminCommand(AdminFlags.Debug)] -public sealed partial class UnlockNodeCommand : LocalizedEntityCommands -{ - [Dependency] private XenoArtifactSystem _artiSystem = default!; - - public override string Command => "unlocknode"; - - public override void Execute(IConsoleShell shell, string argStr, string[] args) - { - if (args.Length != 2) - { - shell.WriteError(Loc.GetString("shell-wrong-arguments-number")); - return; - } - - if (!NetEntity.TryParse(args[1], out var netNode) || !EntityManager.TryGetEntity(netNode, out var entityUid)) - { - shell.WriteError(Loc.GetString("shell-could-not-find-entity-with-uid", ("uid", args[1]))); - return; - } - - _artiSystem.SetNodeUnlocked(entityUid.Value); - } - - public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) - { - switch (args.Length) - { - case 1: - { - var query = EntityManager.EntityQueryEnumerator(); - var completionOptions = new List(); - while (query.MoveNext(out var uid, out _)) - { - completionOptions.Add(new CompletionOption(uid.ToString())); - } - - return CompletionResult.FromHintOptions(completionOptions, Loc.GetString("cmd-unlocknode-artifact-hint")); - } - case 2 when - NetEntity.TryParse(args[0], out var netEnt) && - EntityManager.TryGetEntity(netEnt, out var artifactUid) && - EntityManager.TryGetComponent(artifactUid, out var comp): - { - var result = new List(); - foreach (var node in _artiSystem.GetAllNodes((artifactUid.Value, comp))) - { - var metaData = EntityManager.MetaQuery.Comp(artifactUid.Value); - var entityUidStr = EntityManager.GetNetEntity(node).ToString(); - var completionOption = new CompletionOption(entityUidStr, metaData.EntityName); - result.Add(completionOption); - } - - return CompletionResult.FromHintOptions(result, Loc.GetString("cmd-unlocknode-node-hint")); - } - default: - return CompletionResult.Empty; - } - } -} diff --git a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs deleted file mode 100644 index 7fd7acca4b..0000000000 --- a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System.Text; -using Content.Server.Administration; -using Content.Shared.Administration; -using Content.Shared.Xenoarchaeology.Artifact.Components; -using Robust.Shared.Map; -using Robust.Shared.Prototypes; -using Robust.Shared.Toolshed; - -namespace Content.Server.Xenoarchaeology.Artifact; - -/// -/// Toolshed commands for manipulating xeno artifact. -/// -[ToolshedCommand, AdminCommand(AdminFlags.Debug)] -public sealed class XenoArtifactCommand : ToolshedCommand -{ - public static readonly EntProtoId ArtifactPrototype = "BaseXenoArtifact"; - - /// List existing artifacts. - [CommandImplementation("list")] - public IEnumerable List() - { - var query = EntityManager.EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out _)) - { - yield return uid; - } - } - - /// - /// Output matrix of artifact nodes and how they are connected. - /// - [CommandImplementation("printMatrix")] - public string PrintMatrix([PipedArgument] EntityUid artifactEntitUid) - { - var comp = EntityManager.GetComponent(artifactEntitUid); - - var nodeCount = comp.NodeVertices.Length; - - var sb = new StringBuilder("\n |"); - for (var i = 0; i < nodeCount; i++) - { - sb.Append($" {i:D2}|"); - } - - AddHorizontalFiller(sb); - - for (var i = 0; i < nodeCount; i++) - { - sb.Append($"\n{i:D2}|"); - for (var j = 0; j < nodeCount; j++) - { - var value = comp.NodeAdjacencyMatrix[i][j] - ? "X" - : " "; - sb.Append($" {value} |"); - } - AddHorizontalFiller(sb); - } - - return sb.ToString(); - - void AddHorizontalFiller(StringBuilder builder) - { - builder.AppendLine(); - builder.Append("--+"); - for (var i = 0; i < nodeCount; i++) - { - builder.Append($"---+"); - } - } - } - - /// Output total research points artifact contains. - [CommandImplementation("totalResearch")] - public int TotalResearch([PipedArgument] EntityUid artifactEntityUid) - { - var artiSys = EntityManager.System(); - var comp = EntityManager.GetComponent(artifactEntityUid); - - var sum = 0; - - var nodes = artiSys.GetAllNodes((artifactEntityUid, comp)); - foreach (var node in nodes) - { - sum += node.Comp.ResearchValue; - } - - return sum; - } - - /// - /// Spawns a bunch of artifacts and gets average total research points they can yield. - /// - [CommandImplementation("averageResearch")] - public float AverageResearch() - { - const int n = 100; - var sum = 0; - - for (var i = 0; i < n; i++) - { - var ent = Spawn(ArtifactPrototype, MapCoordinates.Nullspace); - sum += TotalResearch(ent); - Del(ent); - } - - return (float) sum / n; - } - - /// Unlocks all nodes of artifact. - [CommandImplementation("unlockAllNodes")] - public void UnlockAllNodes([PipedArgument] EntityUid artifactEntityUid) - { - var artiSys = EntityManager.System(); - var comp = EntityManager.GetComponent(artifactEntityUid); - - var nodes = artiSys.GetAllNodes((artifactEntityUid, comp)); - foreach (var node in nodes) - { - artiSys.SetNodeUnlocked((node, node.Comp)); - } - } -} diff --git a/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs b/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs index f54a13d162..73c57776b0 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs @@ -1,10 +1,11 @@ -using System.Diagnostics.CodeAnalysis; using Content.Shared.Rejuvenate; using Content.Shared.StatusEffectNew.Components; +using Content.Shared.Toolshed.TypeParsers; using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using System.Diagnostics.CodeAnalysis; namespace Content.Shared.StatusEffectNew; @@ -21,6 +22,8 @@ public sealed partial class StatusEffectsSystem : EntitySystem [Dependency] private EntityQuery _containerQuery = default!; [Dependency] private EntityQuery _effectQuery = default!; + // TODO: https://github.com/space-wizards/space-station-14/issues/45060 + [Access(typeof(StatusEffectCompletionParser), Other = AccessPermissions.None)] public readonly HashSet StatusEffectPrototypes = []; public override void Initialize() diff --git a/Content.Shared/Toolshed/TypeParsers/StatusEffectCompletionParser.cs b/Content.Shared/Toolshed/TypeParsers/StatusEffectCompletionParser.cs new file mode 100644 index 0000000000..cff13d70e0 --- /dev/null +++ b/Content.Shared/Toolshed/TypeParsers/StatusEffectCompletionParser.cs @@ -0,0 +1,19 @@ +using Content.Shared.StatusEffectNew; +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; + +public sealed partial class StatusEffectCompletionParser : CustomCompletionParser +{ + [Dependency] private IEntityManager _entityManager = default!; + + public override CompletionResult? TryAutocomplete(ParserContext ctx, CommandArgument? arg) + { + var statusEffects = _entityManager.System(); + return CompletionResult.FromHintOptions(statusEffects.StatusEffectPrototypes, GetArgHint(arg)); + } +} diff --git a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs new file mode 100644 index 0000000000..23266f7a5d --- /dev/null +++ b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactNodeParser.cs @@ -0,0 +1,66 @@ +using System.Linq; +using Content.Shared.Xenoarchaeology.Artifact; +using Content.Shared.Xenoarchaeology.Artifact.Components; +using Robust.Shared.Console; +using Robust.Shared.Toolshed; +using Robust.Shared.Toolshed.Syntax; +using Robust.Shared.Toolshed.TypeParsers; + +namespace Content.Shared.Toolshed.TypeParsers.XenoArtifact; + +/// +/// Argument parser for toolshed commands, which should autocomplete artifact nodes that exists on artifact. +/// +public sealed partial class XenoArtifactNodeParser : CustomCompletionParser<(Entity, Entity)> +{ + [Dependency] private IEntityManager _entityManager = default!; + + /// + public override CompletionResult? TryAutocomplete(ParserContext ctx, CommandArgument? arg) + { + if (!Toolshed.TryParse>(ctx, out var artifactEnt)) + { + return GetHintedEntities(arg); + } + + var hint = ToolshedCommand.GetArgHint(arg, typeof(Entity)); + + var artifact = _entityManager.System(); + var list = artifact.GetAllNodes(artifactEnt) + .Select( + node => + { + var metadata = _entityManager.GetComponent(node); + var entDescription = Loc.GetString(metadata.EntityDescription); + return new CompletionOption( + node.Owner.ToString(), + Loc.GetString( + "command-xenoartifact-common-node-hint", + ("depth", node.Comp.Depth), + ("nodeId", artifact.GetNodeId(node.Owner)), + ("nodeDetail", entDescription) + ) + ); + }); + + return CompletionResult.FromHintOptions(list, hint); + } + + private CompletionResult? GetHintedEntities(CommandArgument? arg) where T : IComponent + { + var hint = ToolshedCommand.GetArgHint(arg, typeof(NetEntity)); + + // Avoid dumping too many entities + if (_entityManager.Count() > 128) + return CompletionResult.FromHint(hint); + + var query = _entityManager.AllEntityQueryEnumerator(); + var list = new List(); + while (query.MoveNext(out _, out var metadata)) + { + list.Add(new CompletionOption(metadata.NetEntity.ToString(), metadata.EntityName)); + } + + return CompletionResult.FromHintOptions(list, hint); + } +} diff --git a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactTypeParser.cs b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactTypeParser.cs new file mode 100644 index 0000000000..73cacb2811 --- /dev/null +++ b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoArtifactTypeParser.cs @@ -0,0 +1,28 @@ +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 will enable choosing between hand-held and +/// stationary artifact types. +/// +public sealed partial class XenoArtifactTypeParser : CustomCompletionParser> +{ + private static readonly EntProtoId ArtifactDummyItem = "DummyArtifactItem"; + private static readonly EntProtoId ArtifactDummyStructure = "DummyArtifactStructure"; + + public override CompletionResult TryAutocomplete(ParserContext ctx, CommandArgument? arg) + { + return CompletionResult.FromHintOptions( + [ + new CompletionOption(ArtifactDummyItem, Loc.GetString("command-spawnartifactwithnode-spawn-artifact-item-hint")), + new CompletionOption(ArtifactDummyStructure, Loc.GetString("command-spawnartifactwithnode-spawn-artifact-structure-hint")), + ], + Loc.GetString("command-spawnartifactwithnode-spawn-artifact-type-hint") + ); + } +} diff --git a/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoEffectParser.cs b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoEffectParser.cs new file mode 100644 index 0000000000..b1cc776d94 --- /dev/null +++ b/Content.Shared/Toolshed/TypeParsers/XenoArtifact/XenoEffectParser.cs @@ -0,0 +1,26 @@ +using Content.Shared.Xenoarchaeology.Artifact; +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 effect. +/// +public sealed partial class XenoEffectParser : CustomCompletionParser> +{ + [Dependency] private IEntityManager _entityManager = default!; + + public override CompletionResult TryAutocomplete(ParserContext ctx, CommandArgument? arg) + { + var hint = ToolshedCommand.GetArgHint(arg, typeof(ProtoId)); + + var artifact = _entityManager.System(); + + return CompletionResult.FromHintOptions(artifact.EffectPrototypeIds, hint); + } +} diff --git a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs index b4da7d5def..cf63b0ec84 100644 --- a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs +++ b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Node.cs @@ -94,8 +94,15 @@ public abstract partial class SharedXenoArtifactSystem { var entProtoId = _entityTable.GetSpawns(ent.Comp.EffectsTable) .First(); + return CreateNode(ent, entProtoId, trigger, depth); + } - AddNode((ent, ent), entProtoId, out var nodeEnt, dirty: false); + /// + /// 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) + { + AddNode((ent, ent), effect, out var nodeEnt, dirty: false); DebugTools.Assert(nodeEnt.HasValue, "Failed to create node on artifact."); var nodeComponent = nodeEnt.Value.Comp; diff --git a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.cs b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.cs index 2cd02a1d13..f8be146ae9 100644 --- a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.cs +++ b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.cs @@ -1,8 +1,10 @@ using Content.Shared.Actions; using Content.Shared.Popups; +using Content.Shared.Toolshed.TypeParsers.XenoArtifact; using Content.Shared.Xenoarchaeology.Artifact.Components; using Robust.Shared.Containers; using Robust.Shared.Network; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -20,9 +22,16 @@ public abstract partial class SharedXenoArtifactSystem : EntitySystem [Dependency] private SharedContainerSystem _container = default!; [Dependency] private SharedPopupSystem _popup = default!; + // TODO: https://github.com/space-wizards/space-station-14/issues/45060 + /// Cached EntProtoIds of all XenoArtifactEffect prototypes. Used for text hints. + [Access(typeof(XenoEffectParser), Other = AccessPermissions.None)] + public readonly HashSet EffectPrototypeIds = []; + /// public override void Initialize() { + SubscribeLocalEvent(OnPrototypesReloaded); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnSelfActivate); @@ -30,6 +39,28 @@ public abstract partial class SharedXenoArtifactSystem : EntitySystem InitializeUnlock(); InitializeXAT(); InitializeXAE(); + + ReloadEffectCache(); + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + if (!args.WasModified()) + return; + + ReloadEffectCache(); + } + + private void ReloadEffectCache() + { + EffectPrototypeIds.Clear(); + + foreach (var entityPrototype in ProtoMan.EnumeratePrototypes()) + { + // all effect prototypes are marked as nodes, as nodes are born from those prototypes + if (entityPrototype.HasComp(Factory) && !entityPrototype.Abstract) + EffectPrototypeIds.Add(entityPrototype.ID); + } } /// diff --git a/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl b/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl index b6fc94adf9..e65443defd 100644 --- a/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl +++ b/Resources/Locale/en-US/commands/toolshed/xenoartifact-command.ftl @@ -1,10 +1,29 @@ command-description-xenoartifact-list = List all EntityUids of spawned artifacts. -command-description-xenoartifact-printMatrix = +command-description-xenoartifact-printmatrix = Prints out matrix that displays all edges between nodes. -command-description-xenoartifact-totalResearch = +command-description-xenoartifact-totalresearch = Gets all research points that can be extracted from artifact currently. -command-description-xenoartifact-averageResearch = +command-description-xenoartifact-averageresearch = Calculates amount of research points average generated xeno artifact will output when fully activated. -command-description-xenoartifact-unlockAllNodes = +command-description-xenoartifact-unlockallnodes = Unlocks all nodes of artifact. + +command-description-xenoartifact-createnode = + Create node in artifact (new on depth 0 or attach next to existing one). +command-description-xenoartifact-createnodeatdepth = + Add a new node to the given artifact. +command-description-xenoartifact-spawnartwithnode = + Spawns a new xeno artifact with single node with the given trigger and effect. +command-description-xenoartifact-unlocknode = + Marks a node as unlocked. +command-description-xenoartifact-removenode = + Removes a node from a xeno artifact. +command-description-xenoartifact-addedge = + Adds an edge between two nodes of a xeno artifact. + +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} diff --git a/Resources/Locale/en-US/commands/unlocknode-command.ftl b/Resources/Locale/en-US/commands/unlocknode-command.ftl deleted file mode 100644 index 5a3b8259dd..0000000000 --- a/Resources/Locale/en-US/commands/unlocknode-command.ftl +++ /dev/null @@ -1,4 +0,0 @@ -cmd-unlocknode-desc = Unlocks a node on a given artifact -cmd-unlocknode-help = unlocknode -cmd-unlocknode-artifact-hint = -cmd-unlocknode-node-hint = diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml index fb2a0aceb2..ea6a16482c 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: [BaseItem, BaseXenoArtifact] id: BaseXenoArtifactItem name: artifact @@ -61,6 +61,15 @@ tableId: XenoArtifactEffectsHandheldOnlyTable weight: 2 +- type: entity + id: DummyArtifactItem + parent: BaseXenoArtifactItem + name: artifact + suffix: Debug + components: + - type: XenoArtifact + isGenerationRequired: false + - type: entity parent: BaseXenoArtifactItem id: ComplexXenoArtifactItem diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_xenoartifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_xenoartifacts.yml index 88a5bf087c..49f33b2cd6 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_xenoartifacts.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_xenoartifacts.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: [BaseStructureDynamic, BaseXenoArtifact] id: BaseXenoArtifactStructure name: artifact @@ -40,6 +40,15 @@ mask: - MachineMask +- type: entity + id: DummyArtifactStructure + parent: BaseXenoArtifactStructure + name: artifact + suffix: Debug + components: + - type: XenoArtifact + isGenerationRequired: false + - type: entity parent: BaseXenoArtifactStructure id: ComplexXenoArtifact