mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-15 03:50:54 +01:00
Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts: # Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs
This commit is contained in:
@@ -87,7 +87,7 @@ public sealed class InstrumentSystem : SharedInstrumentSystem
|
||||
if (!Resolve(uid, ref instrument) || instrument.Renderer == null)
|
||||
return;
|
||||
|
||||
instrument.Renderer.TrackingEntity = instrument.Owner;
|
||||
instrument.Renderer.TrackingEntity = uid;
|
||||
instrument.Renderer.DisablePercussionChannel = !instrument.AllowPercussion;
|
||||
instrument.Renderer.DisableProgramChangeEvent = !instrument.AllowProgramChange;
|
||||
|
||||
@@ -127,7 +127,9 @@ public sealed class InstrumentSystem : SharedInstrumentSystem
|
||||
|
||||
// We dispose of the synth two seconds from now to allow the last notes to stop from playing.
|
||||
// Don't use timers bound to the entity in case it is getting deleted.
|
||||
Timer.Spawn(2000, () => { renderer?.Dispose(); });
|
||||
if (renderer != null)
|
||||
Timer.Spawn(2000, () => { renderer.Dispose(); });
|
||||
|
||||
instrument.Renderer = null;
|
||||
instrument.MidiEventBuffer.Clear();
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
|
||||
return;
|
||||
|
||||
_cuffable.Uncuff(component.ImplantedEntity.Value, cuffs.LastAddedCuffs, cuffs.LastAddedCuffs);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
#region Relays
|
||||
|
||||
@@ -4,57 +4,73 @@ using Content.Shared.Administration;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Nuke.Commands
|
||||
namespace Content.Server.Nuke.Commands;
|
||||
|
||||
[UsedImplicitly]
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class ToggleNukeCommand : LocalizedCommands
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class ToggleNukeCommand : IConsoleCommand
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
public override string Command => "nukearm";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
public string Command => "nukearm";
|
||||
public string Description => "Toggle nuclear bomb timer. You can set timer directly. Uid is optional.";
|
||||
public string Help => "nukearm <timer> <uid>";
|
||||
EntityUid bombUid;
|
||||
NukeComponent? bomb = null;
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
if (args.Length >= 2)
|
||||
{
|
||||
EntityUid bombUid;
|
||||
NukeComponent? bomb = null;
|
||||
|
||||
if (args.Length >= 2)
|
||||
if (!EntityUid.TryParse(args[1], out bombUid))
|
||||
{
|
||||
if (!EntityUid.TryParse(args[1], out bombUid))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||
return;
|
||||
}
|
||||
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var bombs = entManager.EntityQuery<NukeComponent>();
|
||||
|
||||
bomb = bombs.FirstOrDefault();
|
||||
if (bomb == null)
|
||||
{
|
||||
shell.WriteError("Can't find any entity with a NukeComponent");
|
||||
return;
|
||||
}
|
||||
|
||||
bombUid = bomb.Owner;
|
||||
}
|
||||
|
||||
var nukeSys = EntitySystem.Get<NukeSystem>();
|
||||
if (args.Length >= 1)
|
||||
{
|
||||
if (!float.TryParse(args[0], out var timer))
|
||||
{
|
||||
shell.WriteError("shell-argument-must-be-number");
|
||||
return;
|
||||
}
|
||||
|
||||
nukeSys.SetRemainingTime(bombUid, timer, bomb);
|
||||
}
|
||||
|
||||
nukeSys.ToggleBomb(bombUid, bomb);
|
||||
}
|
||||
else
|
||||
{
|
||||
var query = _entManager.EntityQueryEnumerator<NukeComponent>();
|
||||
|
||||
while (query.MoveNext(out bombUid, out bomb))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (bomb == null)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-nukearm-not-found"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var nukeSys = _entManager.System<NukeSystem>();
|
||||
|
||||
if (args.Length >= 1)
|
||||
{
|
||||
if (!float.TryParse(args[0], out var timer))
|
||||
{
|
||||
shell.WriteError("shell-argument-must-be-number");
|
||||
return;
|
||||
}
|
||||
|
||||
nukeSys.SetRemainingTime(bombUid, timer, bomb);
|
||||
}
|
||||
|
||||
nukeSys.ToggleBomb(bombUid, bomb);
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
return CompletionResult.FromHint(Loc.GetString(Loc.GetString("cmd-nukearm-1-help")));
|
||||
}
|
||||
|
||||
if (args.Length == 2)
|
||||
{
|
||||
return CompletionResult.FromHintOptions(CompletionHelper.Components<NukeComponent>(args[1]), Loc.GetString("cmd-nukearm-2-help"));
|
||||
}
|
||||
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ using Content.Shared.MachineLinking.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Research.Components;
|
||||
using Content.Shared.Xenoarchaeology.Equipment;
|
||||
using Content.Shared.Xenoarchaeology.XenoArtifacts;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -31,6 +33,7 @@ namespace Content.Server.Xenoarchaeology.Equipment.Systems;
|
||||
public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambienntSound = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
@@ -74,7 +77,8 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var (active, scan) in EntityQuery<ActiveArtifactAnalyzerComponent, ArtifactAnalyzerComponent>())
|
||||
var query = EntityQueryEnumerator<ActiveArtifactAnalyzerComponent, ArtifactAnalyzerComponent>();
|
||||
while (query.MoveNext(out var uid, out var active, out var scan))
|
||||
{
|
||||
if (scan.Console != null)
|
||||
UpdateUserInterface(scan.Console.Value);
|
||||
@@ -82,7 +86,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
if (_timing.CurTime - active.StartTime < (scan.AnalysisDuration * scan.AnalysisDurationMulitplier))
|
||||
continue;
|
||||
|
||||
FinishScan(scan.Owner, scan, active);
|
||||
FinishScan(uid, scan, active);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +143,9 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
}
|
||||
else if (TryComp<ArtifactComponent>(component.LastAnalyzedArtifact, out var artifact))
|
||||
{
|
||||
var lastNode = (ArtifactNode?) artifact.CurrentNode?.Clone();
|
||||
var lastNode = artifact.CurrentNodeId == null
|
||||
? null
|
||||
: (ArtifactNode?) _artifact.GetNodeFromId(artifact.CurrentNodeId.Value, artifact).Clone();
|
||||
component.LastAnalyzedNode = lastNode;
|
||||
component.LastAnalyzerPointValue = _artifact.GetResearchPointValue(component.LastAnalyzedArtifact.Value, artifact);
|
||||
}
|
||||
@@ -298,17 +304,20 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
|
||||
msg.PushNewline();
|
||||
var needSecondNewline = false;
|
||||
if (n.Trigger.TriggerHint != null)
|
||||
|
||||
var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(n.Trigger);
|
||||
if (triggerProto.TriggerHint != null)
|
||||
{
|
||||
msg.AddMarkup(Loc.GetString("analysis-console-info-trigger",
|
||||
("trigger", Loc.GetString(n.Trigger.TriggerHint))) + "\n");
|
||||
("trigger", Loc.GetString(triggerProto.TriggerHint))) + "\n");
|
||||
needSecondNewline = true;
|
||||
}
|
||||
|
||||
if (n.Effect.EffectHint != null)
|
||||
var effectproto = _prototype.Index<ArtifactEffectPrototype>(n.Effect);
|
||||
if (effectproto.EffectHint != null)
|
||||
{
|
||||
msg.AddMarkup(Loc.GetString("analysis-console-info-effect",
|
||||
("effect", Loc.GetString(n.Effect.EffectHint))) + "\n");
|
||||
("effect", Loc.GetString(effectproto.EffectHint))) + "\n");
|
||||
needSecondNewline = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public sealed class NodeScannerSystem : EntitySystem
|
||||
if (!args.CanReach || args.Target == null)
|
||||
return;
|
||||
|
||||
if (!TryComp<ArtifactComponent>(args.Target, out var artifact) || artifact.CurrentNode == null)
|
||||
if (!TryComp<ArtifactComponent>(args.Target, out var artifact) || artifact.CurrentNodeId == null)
|
||||
return;
|
||||
|
||||
if (args.Handled)
|
||||
@@ -33,6 +33,6 @@ public sealed class NodeScannerSystem : EntitySystem
|
||||
var target = args.Target.Value;
|
||||
_useDelay.BeginDelay(uid);
|
||||
_popupSystem.PopupEntity(Loc.GetString("node-scan-popup",
|
||||
("id", $"{artifact.CurrentNode.Id}")), target);
|
||||
("id", $"{artifact.CurrentNodeId}")), target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.Xenoarchaeology.XenoArtifacts;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts;
|
||||
|
||||
@@ -7,16 +8,16 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts;
|
||||
public sealed class ArtifactComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The artifact's node tree.
|
||||
/// Every node contained in the tree
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ArtifactTree? NodeTree;
|
||||
[DataField("nodeTree"), ViewVariables]
|
||||
public List<ArtifactNode> NodeTree = new();
|
||||
|
||||
/// <summary>
|
||||
/// The current node the artifact is on.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ArtifactNode? CurrentNode;
|
||||
[DataField("currentNodeId"), ViewVariables]
|
||||
public int? CurrentNodeId;
|
||||
|
||||
#region Node Tree Gen
|
||||
/// <summary>
|
||||
@@ -35,21 +36,20 @@ public sealed class ArtifactComponent : Component
|
||||
/// <summary>
|
||||
/// Cooldown time between artifact activations (in seconds).
|
||||
/// </summary>
|
||||
[DataField("timer", customTypeSerializer: typeof(TimespanSerializer))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("timer"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan CooldownTime = TimeSpan.FromSeconds(5);
|
||||
|
||||
/// <summary>
|
||||
/// Is this artifact under some suppression device?
|
||||
/// f true, will ignore all trigger activations attempts.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("isSuppressed"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool IsSuppressed;
|
||||
|
||||
/// <summary>
|
||||
/// The last time the artifact was activated.
|
||||
/// </summary>
|
||||
[DataField("lastActivationTime", customTypeSerializer: typeof(TimespanSerializer))]
|
||||
[DataField("lastActivationTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan LastActivationTime;
|
||||
|
||||
/// <summary>
|
||||
@@ -72,25 +72,6 @@ public sealed class ArtifactComponent : Component
|
||||
public float PointDangerMultiplier = 1.35f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A tree of nodes.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed class ArtifactTree
|
||||
{
|
||||
/// <summary>
|
||||
/// The first node of the tree
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ArtifactNode StartNode = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Every node contained in the tree
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public readonly List<ArtifactNode> AllNodes = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single "node" of an artifact that contains various data about it.
|
||||
/// </summary>
|
||||
@@ -98,51 +79,51 @@ public sealed class ArtifactTree
|
||||
public sealed class ArtifactNode : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// A numeric id corresponding to each node. used for display purposes
|
||||
/// A numeric id corresponding to each node.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("id"), ViewVariables]
|
||||
public int Id;
|
||||
|
||||
/// <summary>
|
||||
/// how "deep" into the node tree. used for generation and price/value calculations
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public int Depth = 0;
|
||||
[DataField("depth"), ViewVariables]
|
||||
public int Depth;
|
||||
|
||||
/// <summary>
|
||||
/// A list of surrounding nodes. Used for tree traversal
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public List<ArtifactNode> Edges = new();
|
||||
[DataField("edges"), ViewVariables]
|
||||
public HashSet<int> Edges = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the node has been entered
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Discovered = false;
|
||||
[DataField("discovered"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Discovered;
|
||||
|
||||
/// <summary>
|
||||
/// The trigger for the node
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ArtifactTriggerPrototype Trigger = default!;
|
||||
[DataField("trigger", customTypeSerializer: typeof(PrototypeIdSerializer<ArtifactTriggerPrototype>), required: true), ViewVariables]
|
||||
public string Trigger = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the node has been triggered
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Triggered = false;
|
||||
[DataField("triggered"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Triggered;
|
||||
|
||||
/// <summary>
|
||||
/// The effect when the node is activated
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ArtifactEffectPrototype Effect = default!;
|
||||
[DataField("effect", customTypeSerializer: typeof(PrototypeIdSerializer<ArtifactEffectPrototype>), required: true), ViewVariables]
|
||||
public string Effect = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Used for storing cumulative information about nodes
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("nodeData"), ViewVariables]
|
||||
public Dictionary<string, object> NodeData = new();
|
||||
|
||||
public object Clone()
|
||||
|
||||
@@ -42,10 +42,10 @@ public partial class ArtifactSystem
|
||||
|
||||
private void OnSelfActivate(EntityUid uid, ArtifactComponent component, ArtifactSelfActivateEvent args)
|
||||
{
|
||||
if (component.CurrentNode == null)
|
||||
if (component.CurrentNodeId == null)
|
||||
return;
|
||||
|
||||
var curNode = component.CurrentNode.Id;
|
||||
var curNode = GetNodeFromId(component.CurrentNodeId.Value, component).Id;
|
||||
_popup.PopupEntity(Loc.GetString("activate-artifact-popup-self", ("node", curNode)), uid, uid);
|
||||
TryActivateArtifact(uid, uid, component);
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ public partial class ArtifactSystem
|
||||
if (!EntityUid.TryParse(args[0], out var uid) || ! int.TryParse(args[1], out var id))
|
||||
return;
|
||||
|
||||
if (!TryComp<ArtifactComponent>(uid, out var artifact) || artifact.NodeTree == null)
|
||||
if (!TryComp<ArtifactComponent>(uid, out var artifact))
|
||||
return;
|
||||
|
||||
if (artifact.NodeTree.AllNodes.FirstOrDefault(n => n.Id == id) is { } node)
|
||||
if (artifact.NodeTree.FirstOrDefault(n => n.Id == id) is { } node)
|
||||
{
|
||||
EnterNode(uid, ref node);
|
||||
}
|
||||
@@ -41,9 +41,9 @@ public partial class ArtifactSystem
|
||||
{
|
||||
if (args.Length == 2 && EntityUid.TryParse(args[0], out var uid))
|
||||
{
|
||||
if (TryComp<ArtifactComponent>(uid, out var artifact) && artifact.NodeTree != null)
|
||||
if (TryComp<ArtifactComponent>(uid, out var artifact))
|
||||
{
|
||||
return CompletionResult.FromHintOptions(artifact.NodeTree.AllNodes.Select(s => s.Id.ToString()), "<node id>");
|
||||
return CompletionResult.FromHintOptions(artifact.NodeTree.Select(s => s.Id.ToString()), "<node id>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,10 +59,10 @@ public partial class ArtifactSystem
|
||||
if (!EntityUid.TryParse(args[0], out var uid))
|
||||
return;
|
||||
|
||||
if (!TryComp<ArtifactComponent>(uid, out var artifact) || artifact.NodeTree == null)
|
||||
if (!TryComp<ArtifactComponent>(uid, out var artifact))
|
||||
return;
|
||||
|
||||
var pointSum = GetResearchPointValue(uid, artifact, true);
|
||||
shell.WriteLine($"Max point value for {ToPrettyString(uid)} with {artifact.NodeTree.AllNodes.Count} nodes: {pointSum}");
|
||||
shell.WriteLine($"Max point value for {ToPrettyString(uid)} with {artifact.NodeTree.Count} nodes: {pointSum}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||
using Content.Shared.Xenoarchaeology.XenoArtifacts;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
@@ -15,13 +16,15 @@ public sealed partial class ArtifactSystem
|
||||
|
||||
private const int MaxEdgesPerNode = 4;
|
||||
|
||||
private readonly HashSet<int> _usedNodeIds = new();
|
||||
|
||||
/// <summary>
|
||||
/// Generate an Artifact tree with fully developed nodes.
|
||||
/// </summary>
|
||||
/// <param name="artifact"></param>
|
||||
/// <param name="tree">The tree being generated.</param>
|
||||
/// <param name="allNodes"></param>
|
||||
/// <param name="nodeAmount">The amount of nodes it has.</param>
|
||||
private void GenerateArtifactNodeTree(EntityUid artifact, ref ArtifactTree tree, int nodeAmount)
|
||||
private void GenerateArtifactNodeTree(EntityUid artifact, ref List<ArtifactNode> allNodes, int nodeAmount)
|
||||
{
|
||||
if (nodeAmount < 1)
|
||||
{
|
||||
@@ -29,19 +32,36 @@ public sealed partial class ArtifactSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var uninitializedNodes = new List<ArtifactNode> { new() };
|
||||
tree.StartNode = uninitializedNodes.First(); //the first node
|
||||
_usedNodeIds.Clear();
|
||||
|
||||
|
||||
var rootNode = new ArtifactNode
|
||||
{
|
||||
Id = GetValidNodeId()
|
||||
};
|
||||
var uninitializedNodes = new List<ArtifactNode> { rootNode };
|
||||
while (uninitializedNodes.Any())
|
||||
{
|
||||
GenerateNode(artifact, ref uninitializedNodes, ref tree, nodeAmount);
|
||||
GenerateNode(artifact, ref uninitializedNodes, ref allNodes, nodeAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetValidNodeId()
|
||||
{
|
||||
var id = _random.Next(10000, 100000);
|
||||
while (_usedNodeIds.Contains(id))
|
||||
{
|
||||
id = _random.Next(10000, 100000);
|
||||
}
|
||||
|
||||
_usedNodeIds.Add(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate an individual node on the tree.
|
||||
/// </summary>
|
||||
private void GenerateNode(EntityUid artifact, ref List<ArtifactNode> uninitializedNodes, ref ArtifactTree tree, int targetNodeAmount)
|
||||
private void GenerateNode(EntityUid artifact, ref List<ArtifactNode> uninitializedNodes, ref List<ArtifactNode> allNodes, int targetNodeAmount)
|
||||
{
|
||||
if (!uninitializedNodes.Any())
|
||||
return;
|
||||
@@ -49,13 +69,10 @@ public sealed partial class ArtifactSystem
|
||||
var node = uninitializedNodes.First();
|
||||
uninitializedNodes.Remove(node);
|
||||
|
||||
//random 5-digit number
|
||||
node.Id = _random.Next(10000, 100000);
|
||||
|
||||
//Generate the connected nodes
|
||||
var maxEdges = Math.Max(1, targetNodeAmount - tree.AllNodes.Count - uninitializedNodes.Count - 1);
|
||||
var maxEdges = Math.Max(1, targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1);
|
||||
maxEdges = Math.Min(maxEdges, MaxEdgesPerNode);
|
||||
var minEdges = Math.Clamp(targetNodeAmount - tree.AllNodes.Count - uninitializedNodes.Count - 1, 0, 1);
|
||||
var minEdges = Math.Clamp(targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1, 0, 1);
|
||||
|
||||
var edgeAmount = _random.Next(minEdges, maxEdges);
|
||||
|
||||
@@ -63,10 +80,11 @@ public sealed partial class ArtifactSystem
|
||||
{
|
||||
var neighbor = new ArtifactNode
|
||||
{
|
||||
Depth = node.Depth + 1
|
||||
Depth = node.Depth + 1,
|
||||
Id = GetValidNodeId()
|
||||
};
|
||||
node.Edges.Add(neighbor);
|
||||
neighbor.Edges.Add(node);
|
||||
node.Edges.Add(neighbor.Id);
|
||||
neighbor.Edges.Add(node.Id);
|
||||
|
||||
uninitializedNodes.Add(neighbor);
|
||||
}
|
||||
@@ -74,13 +92,13 @@ public sealed partial class ArtifactSystem
|
||||
node.Trigger = GetRandomTrigger(artifact, ref node);
|
||||
node.Effect = GetRandomEffect(artifact, ref node);
|
||||
|
||||
tree.AllNodes.Add(node);
|
||||
allNodes.Add(node);
|
||||
}
|
||||
|
||||
//yeah these two functions are near duplicates but i don't
|
||||
//want to implement an interface or abstract parent
|
||||
|
||||
private ArtifactTriggerPrototype GetRandomTrigger(EntityUid artifact, ref ArtifactNode node)
|
||||
private string GetRandomTrigger(EntityUid artifact, ref ArtifactNode node)
|
||||
{
|
||||
var allTriggers = _prototype.EnumeratePrototypes<ArtifactTriggerPrototype>()
|
||||
.Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList();
|
||||
@@ -91,10 +109,10 @@ public sealed partial class ArtifactSystem
|
||||
var targetTriggers = allTriggers
|
||||
.Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList();
|
||||
|
||||
return _random.Pick(targetTriggers);
|
||||
return _random.Pick(targetTriggers).ID;
|
||||
}
|
||||
|
||||
private ArtifactEffectPrototype GetRandomEffect(EntityUid artifact, ref ArtifactNode node)
|
||||
private string GetRandomEffect(EntityUid artifact, ref ArtifactNode node)
|
||||
{
|
||||
var allEffects = _prototype.EnumeratePrototypes<ArtifactEffectPrototype>()
|
||||
.Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList();
|
||||
@@ -105,7 +123,7 @@ public sealed partial class ArtifactSystem
|
||||
var targetEffects = allEffects
|
||||
.Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList();
|
||||
|
||||
return _random.Pick(targetEffects);
|
||||
return _random.Pick(targetEffects).ID;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
@@ -156,14 +174,17 @@ public sealed partial class ArtifactSystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
if (component.CurrentNode != null)
|
||||
if (component.CurrentNodeId != null)
|
||||
{
|
||||
ExitNode(uid, component);
|
||||
}
|
||||
|
||||
component.CurrentNode = node;
|
||||
component.CurrentNodeId = node.Id;
|
||||
|
||||
var allComponents = node.Effect.Components.Concat(node.Effect.PermanentComponents).Concat(node.Trigger.Components);
|
||||
var trigger = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
|
||||
var effect = _prototype.Index<ArtifactEffectPrototype>(node.Effect);
|
||||
|
||||
var allComponents = effect.Components.Concat(effect.PermanentComponents).Concat(trigger.Components);
|
||||
foreach (var (name, entry) in allComponents)
|
||||
{
|
||||
var reg = _componentFactory.GetRegistration(name);
|
||||
@@ -171,7 +192,7 @@ public sealed partial class ArtifactSystem
|
||||
if (node.Discovered && EntityManager.HasComponent(uid, reg.Type))
|
||||
{
|
||||
// Don't re-add permanent components unless this is the first time you've entered this node
|
||||
if (node.Effect.PermanentComponents.ContainsKey(name))
|
||||
if (effect.PermanentComponents.ContainsKey(name))
|
||||
continue;
|
||||
|
||||
EntityManager.RemoveComponent(uid, reg.Type);
|
||||
@@ -187,7 +208,7 @@ public sealed partial class ArtifactSystem
|
||||
}
|
||||
|
||||
node.Discovered = true;
|
||||
RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNode.Id));
|
||||
RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNodeId.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,16 +219,31 @@ public sealed partial class ArtifactSystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
var node = component.CurrentNode;
|
||||
if (node == null)
|
||||
if (component.CurrentNodeId == null)
|
||||
return;
|
||||
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
|
||||
|
||||
foreach (var name in node.Effect.Components.Keys.Concat(node.Trigger.Components.Keys))
|
||||
var trigger = _prototype.Index<ArtifactTriggerPrototype>(currentNode.Trigger);
|
||||
var effect = _prototype.Index<ArtifactEffectPrototype>(currentNode.Effect);
|
||||
|
||||
foreach (var name in effect.Components.Keys.Concat(trigger.Components.Keys))
|
||||
{
|
||||
var comp = _componentFactory.GetRegistration(name);
|
||||
EntityManager.RemoveComponentDeferred(uid, comp.Type);
|
||||
}
|
||||
|
||||
component.CurrentNode = null;
|
||||
component.CurrentNodeId = null;
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public ArtifactNode GetNodeFromId(int id, ArtifactComponent component)
|
||||
{
|
||||
return component.NodeTree.First(x => x.Id == id);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public ArtifactNode GetNodeFromId(int id, IEnumerable<ArtifactNode> nodes)
|
||||
{
|
||||
return nodes.First(x => x.Id == id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Xenoarchaeology.Equipment.Components;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
|
||||
using Content.Shared.Xenoarchaeology.XenoArtifacts;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -46,13 +47,10 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
/// </remarks>
|
||||
private void GetPrice(EntityUid uid, ArtifactComponent component, ref PriceCalculationEvent args)
|
||||
{
|
||||
if (component.NodeTree == null)
|
||||
return;
|
||||
|
||||
var price = component.NodeTree.AllNodes.Sum(x => GetNodePrice(x, component));
|
||||
var price = component.NodeTree.Sum(x => GetNodePrice(x, component));
|
||||
|
||||
// 25% bonus for fully exploring every node.
|
||||
var fullyExploredBonus = component.NodeTree.AllNodes.Any(x => !x.Triggered) ? 1 : 1.25f;
|
||||
var fullyExploredBonus = component.NodeTree.Any(x => !x.Triggered) ? 1 : 1.25f;
|
||||
|
||||
args.Price =+ price * fullyExploredBonus;
|
||||
}
|
||||
@@ -62,10 +60,13 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
if (!node.Discovered) //no money for undiscovered nodes.
|
||||
return 0;
|
||||
|
||||
var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
|
||||
var effectProto = _prototype.Index<ArtifactEffectPrototype>(node.Effect);
|
||||
|
||||
//quarter price if not triggered
|
||||
var priceMultiplier = node.Triggered ? 1f : 0.25f;
|
||||
//the danger is the average of node depth, effect danger, and trigger danger.
|
||||
var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3;
|
||||
var nodeDanger = (node.Depth + effectProto.TargetDepth + triggerProto.TargetDepth) / 3;
|
||||
|
||||
var price = MathF.Pow(2f, nodeDanger) * component.PricePerNode * priceMultiplier;
|
||||
return price;
|
||||
@@ -86,11 +87,11 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
/// </remarks>
|
||||
public int GetResearchPointValue(EntityUid uid, ArtifactComponent? component = null, bool getMaxPrice = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component) || component.NodeTree == null)
|
||||
if (!Resolve(uid, ref component))
|
||||
return 0;
|
||||
|
||||
var sumValue = component.NodeTree.AllNodes.Sum(n => GetNodePointValue(n, component, getMaxPrice));
|
||||
var fullyExploredBonus = component.NodeTree.AllNodes.All(x => x.Triggered) || getMaxPrice ? 1.25f : 1;
|
||||
var sumValue = component.NodeTree.Sum(n => GetNodePointValue(n, component, getMaxPrice));
|
||||
var fullyExploredBonus = component.NodeTree.All(x => x.Triggered) || getMaxPrice ? 1.25f : 1;
|
||||
|
||||
var pointValue = (int) (sumValue * fullyExploredBonus);
|
||||
return pointValue;
|
||||
@@ -109,7 +110,11 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
|
||||
valueDeduction = !node.Triggered ? 0.25f : 1;
|
||||
}
|
||||
var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3;
|
||||
|
||||
var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
|
||||
var effectProto = _prototype.Index<ArtifactEffectPrototype>(node.Effect);
|
||||
|
||||
var nodeDanger = (node.Depth + effectProto.TargetDepth + triggerProto.TargetDepth) / 3;
|
||||
return component.PointsPerNode * MathF.Pow(component.PointDangerMultiplier, nodeDanger) * valueDeduction;
|
||||
}
|
||||
|
||||
@@ -121,10 +126,9 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
{
|
||||
var nodeAmount = _random.Next(component.NodesMin, component.NodesMax);
|
||||
|
||||
component.NodeTree = new ArtifactTree();
|
||||
|
||||
GenerateArtifactNodeTree(uid, ref component.NodeTree, nodeAmount);
|
||||
EnterNode(uid, ref component.NodeTree.StartNode, component);
|
||||
var firstNode = GetRootNode(component.NodeTree);
|
||||
EnterNode(uid, ref firstNode, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -162,7 +166,7 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
if (component.CurrentNode == null)
|
||||
if (component.CurrentNodeId == null)
|
||||
return;
|
||||
|
||||
component.LastActivationTime = _gameTiming.CurTime;
|
||||
@@ -173,8 +177,10 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
};
|
||||
RaiseLocalEvent(uid, ev, true);
|
||||
|
||||
component.CurrentNode.Triggered = true;
|
||||
if (component.CurrentNode.Edges.Any())
|
||||
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
|
||||
|
||||
currentNode.Triggered = true;
|
||||
if (currentNode.Edges.Any())
|
||||
{
|
||||
var newNode = GetNewNode(uid, component);
|
||||
if (newNode == null)
|
||||
@@ -185,10 +191,18 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
|
||||
private ArtifactNode? GetNewNode(EntityUid uid, ArtifactComponent component)
|
||||
{
|
||||
if (component.CurrentNode == null)
|
||||
if (component.CurrentNodeId == null)
|
||||
return null;
|
||||
|
||||
var allNodes = component.CurrentNode.Edges;
|
||||
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
|
||||
|
||||
var allNodes = currentNode.Edges;
|
||||
Logger.Debug($"our node: {currentNode.Id}");
|
||||
Logger.Debug("other nodes:");
|
||||
foreach (var other in allNodes)
|
||||
{
|
||||
Logger.Debug($"{other}");
|
||||
}
|
||||
|
||||
if (TryComp<BiasedArtifactComponent>(uid, out var bias) &&
|
||||
TryComp<TraversalDistorterComponent>(bias.Provider, out var trav) &&
|
||||
@@ -198,26 +212,26 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
switch (trav.BiasDirection)
|
||||
{
|
||||
case BiasDirection.In:
|
||||
var foo = allNodes.Where(x => x.Depth < component.CurrentNode.Depth).ToList();
|
||||
var foo = allNodes.Where(x => GetNodeFromId(x, component).Depth < currentNode.Depth).ToHashSet();
|
||||
if (foo.Any())
|
||||
allNodes = foo;
|
||||
break;
|
||||
case BiasDirection.Out:
|
||||
var bar = allNodes.Where(x => x.Depth > component.CurrentNode.Depth).ToList();
|
||||
var bar = allNodes.Where(x => GetNodeFromId(x, component).Depth > currentNode.Depth).ToHashSet();
|
||||
if (bar.Any())
|
||||
allNodes = bar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var undiscoveredNodes = allNodes.Where(x => !x.Discovered).ToList();
|
||||
var undiscoveredNodes = allNodes.Where(x => GetNodeFromId(x, component).Discovered).ToList();
|
||||
var newNode = _random.Pick(allNodes);
|
||||
if (undiscoveredNodes.Any() && _random.Prob(0.75f))
|
||||
{
|
||||
newNode = _random.Pick(undiscoveredNodes);
|
||||
}
|
||||
|
||||
return newNode;
|
||||
return GetNodeFromId(newNode, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -236,10 +250,11 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (component.CurrentNode == null)
|
||||
if (component.CurrentNodeId == null)
|
||||
return false;
|
||||
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
|
||||
|
||||
if (component.CurrentNode.NodeData.TryGetValue(key, out var dat) && dat is T value)
|
||||
if (currentNode.NodeData.TryGetValue(key, out var dat) && dat is T value)
|
||||
{
|
||||
data = value;
|
||||
return true;
|
||||
@@ -260,10 +275,21 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
if (component.CurrentNode == null)
|
||||
if (component.CurrentNodeId == null)
|
||||
return;
|
||||
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
|
||||
|
||||
component.CurrentNode.NodeData[key] = value;
|
||||
currentNode.NodeData[key] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base node (depth 0) of an artifact's node graph
|
||||
/// </summary>
|
||||
/// <param name="allNodes"></param>
|
||||
/// <returns></returns>
|
||||
public ArtifactNode GetRootNode(List<ArtifactNode> allNodes)
|
||||
{
|
||||
return allNodes.First(n => n.Depth == 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -272,10 +298,11 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
private void OnRoundEnd(RoundEndTextAppendEvent ev)
|
||||
{
|
||||
return; // Corvax: No fun allowed
|
||||
foreach (var artifactComp in EntityQuery<ArtifactComponent>())
|
||||
var query = EntityQueryEnumerator<ArtifactComponent>();
|
||||
while (query.MoveNext(out var ent, out var artifactComp))
|
||||
{
|
||||
artifactComp.CooldownTime = TimeSpan.Zero;
|
||||
var timerTrigger = EnsureComp<ArtifactTimerTriggerComponent>(artifactComp.Owner);
|
||||
var timerTrigger = EnsureComp<ArtifactTimerTriggerComponent>(ent);
|
||||
timerTrigger.ActivationRate = TimeSpan.FromSeconds(0.5); //HAHAHAHAHAHAHAHAHAH -emo
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
Entries:
|
||||
- author: Vordenburg
|
||||
changes:
|
||||
- {message: Toy ammunition boxes can be re-filled again., type: Fix}
|
||||
id: 2740
|
||||
time: '2022-12-10T03:43:19.0000000+00:00'
|
||||
- author: metalgearsloth
|
||||
changes:
|
||||
- {message: Rat servants will pathfind under doors again., type: Fix}
|
||||
@@ -2922,3 +2917,8 @@ Entries:
|
||||
- {message: modified and added stack sprites for wood, type: Tweak}
|
||||
id: 3239
|
||||
time: '2023-03-24T02:26:20.0000000+00:00'
|
||||
- author: Mr0maks
|
||||
changes:
|
||||
- {message: Fix freedom implant charges not being used., type: Fix}
|
||||
id: 3240
|
||||
time: '2023-03-24T03:07:21.0000000+00:00'
|
||||
|
||||
6
Resources/Locale/en-US/nuke/nuke-command.ftl
Normal file
6
Resources/Locale/en-US/nuke/nuke-command.ftl
Normal file
@@ -0,0 +1,6 @@
|
||||
cmd-nukearm-desc = Toggle nuclear bomb timer. You can set timer directly. Uid is optional.
|
||||
cmd-nukearm-help = nukearm <timer> <uid>
|
||||
cmd-nukearm-not-found = Can't find any entity with a NukeComponent.
|
||||
|
||||
cmd-nukearm-1-help = Time (in seconds)
|
||||
cmd-nukearm-2-help = Nuke
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user