Add "Begin Deconstruction" verb, unfinished particle accelerator bits will tell you how to finish them (#2706)
* More Construction Pieces: Default construction targets * More Construction Pieces: Unfinished particle accelerator will tell you how to finish it * More Construction Pieces: Construction system actually pathfinds any-to-any * More Construction Pieces: Verb to begin deconstruction of an object
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
using Content.Shared.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.GameObjects.Verbs;
|
||||||
|
using Content.Shared.Interfaces;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Components;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Construction
|
||||||
|
{
|
||||||
|
public partial class ConstructionComponent
|
||||||
|
{
|
||||||
|
[Verb]
|
||||||
|
public sealed class DeconstructibleVerb : Verb<ConstructionComponent>
|
||||||
|
{
|
||||||
|
protected override void GetData(IEntity user, ConstructionComponent component, VerbData data)
|
||||||
|
{
|
||||||
|
if (!ActionBlockerSystem.CanInteract(user))
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((component.Target != null) && (component.Target.Name == component.DeconstructionNodeIdentifier)) ||
|
||||||
|
((component.Node != null) && (component.Node.Name == component.DeconstructionNodeIdentifier)))
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.CategoryData = VerbCategories.Construction;
|
||||||
|
data.Text = Loc.GetString("Begin deconstructing");
|
||||||
|
data.IconTexture = "/Textures/Interface/VerbIcons/rotate_ccw.svg.96dpi.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, ConstructionComponent component)
|
||||||
|
{
|
||||||
|
component.SetNewTarget(component.DeconstructionNodeIdentifier);
|
||||||
|
if (component.Target == null)
|
||||||
|
{
|
||||||
|
// Maybe check, but on the flip-side a better solution might be to not make it undeconstructible in the first place, no?
|
||||||
|
component.Owner.PopupMessage(user, Loc.GetString("There is no way to deconstruct this."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
component.Owner.PopupMessage(user, Loc.GetString("Examine to see instructions."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ using Robust.Shared.ViewVariables;
|
|||||||
namespace Content.Server.GameObjects.Components.Construction
|
namespace Content.Server.GameObjects.Components.Construction
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class ConstructionComponent : Component, IExamine, IInteractUsing
|
public partial class ConstructionComponent : Component, IExamine, IInteractUsing
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
@@ -39,6 +39,7 @@ namespace Content.Server.GameObjects.Components.Construction
|
|||||||
private TaskCompletionSource<object>? _handlingTask = null;
|
private TaskCompletionSource<object>? _handlingTask = null;
|
||||||
private string _graphIdentifier = string.Empty;
|
private string _graphIdentifier = string.Empty;
|
||||||
private string _startingNodeIdentifier = string.Empty;
|
private string _startingNodeIdentifier = string.Empty;
|
||||||
|
private string _startingTargetNodeIdentifier = string.Empty;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private HashSet<string> _containers = new();
|
private HashSet<string> _containers = new();
|
||||||
@@ -79,6 +80,9 @@ namespace Content.Server.GameObjects.Components.Construction
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public int EdgeStep { get; private set; } = 0;
|
public int EdgeStep { get; private set; } = 0;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public string DeconstructionNodeIdentifier { get; private set; } = "start";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
{
|
{
|
||||||
@@ -86,6 +90,8 @@ namespace Content.Server.GameObjects.Components.Construction
|
|||||||
|
|
||||||
serializer.DataField(ref _graphIdentifier, "graph", string.Empty);
|
serializer.DataField(ref _graphIdentifier, "graph", string.Empty);
|
||||||
serializer.DataField(ref _startingNodeIdentifier, "node", string.Empty);
|
serializer.DataField(ref _startingNodeIdentifier, "node", string.Empty);
|
||||||
|
serializer.DataField(ref _startingTargetNodeIdentifier, "defaultTarget", string.Empty);
|
||||||
|
serializer.DataField(this, x => x.DeconstructionNodeIdentifier, "deconstructionTarget", "start");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -495,6 +501,9 @@ namespace Content.Server.GameObjects.Components.Construction
|
|||||||
{
|
{
|
||||||
Logger.Error($"Couldn't find prototype {_graphIdentifier} in construction component!");
|
Logger.Error($"Couldn't find prototype {_graphIdentifier} in construction component!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(_startingTargetNodeIdentifier))
|
||||||
|
SetNewTarget(_startingTargetNodeIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Startup()
|
protected override void Startup()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Content.Shared.Construction
|
|||||||
{
|
{
|
||||||
private readonly Dictionary<string, ConstructionGraphNode> _nodes = new();
|
private readonly Dictionary<string, ConstructionGraphNode> _nodes = new();
|
||||||
private readonly Dictionary<ValueTuple<string, string>, ConstructionGraphNode[]> _paths = new();
|
private readonly Dictionary<ValueTuple<string, string>, ConstructionGraphNode[]> _paths = new();
|
||||||
private Dictionary<ConstructionGraphNode, ConstructionGraphNode> _pathfinding = new();
|
private readonly Dictionary<string, Dictionary<ConstructionGraphNode, ConstructionGraphNode>> _pathfinding = new();
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public string ID { get; private set; }
|
public string ID { get; private set; }
|
||||||
@@ -44,8 +44,6 @@ namespace Content.Shared.Construction
|
|||||||
|
|
||||||
if(string.IsNullOrEmpty(Start) || !_nodes.ContainsKey(Start))
|
if(string.IsNullOrEmpty(Start) || !_nodes.ContainsKey(Start))
|
||||||
throw new InvalidDataException($"Starting node for construction graph {ID} is null, empty or invalid!");
|
throw new InvalidDataException($"Starting node for construction graph {ID} is null, empty or invalid!");
|
||||||
|
|
||||||
_pathfinding = Pathfind(Start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstructionGraphEdge Edge(string startNode, string nextNode)
|
public ConstructionGraphEdge Edge(string startNode, string nextNode)
|
||||||
@@ -61,6 +59,20 @@ namespace Content.Shared.Construction
|
|||||||
if (_paths.ContainsKey(tuple))
|
if (_paths.ContainsKey(tuple))
|
||||||
return _paths[tuple];
|
return _paths[tuple];
|
||||||
|
|
||||||
|
// Get graph given the current start.
|
||||||
|
|
||||||
|
Dictionary<ConstructionGraphNode, ConstructionGraphNode> pathfindingForStart;
|
||||||
|
if (_pathfinding.ContainsKey(startNode))
|
||||||
|
{
|
||||||
|
pathfindingForStart = _pathfinding[startNode];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathfindingForStart = _pathfinding[startNode] = PathsForStart(startNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow the chain backwards.
|
||||||
|
|
||||||
var start = _nodes[startNode];
|
var start = _nodes[startNode];
|
||||||
var finish = _nodes[finishNode];
|
var finish = _nodes[finishNode];
|
||||||
|
|
||||||
@@ -71,14 +83,14 @@ namespace Content.Shared.Construction
|
|||||||
path.Add(current);
|
path.Add(current);
|
||||||
|
|
||||||
// No path.
|
// No path.
|
||||||
if (current == null || !_pathfinding.ContainsKey(current))
|
if (current == null || !pathfindingForStart.ContainsKey(current))
|
||||||
{
|
{
|
||||||
// We remember this for next time.
|
// We remember this for next time.
|
||||||
_paths[tuple] = null;
|
_paths[tuple] = null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = _pathfinding[current];
|
current = pathfindingForStart[current];
|
||||||
}
|
}
|
||||||
|
|
||||||
path.Reverse();
|
path.Reverse();
|
||||||
@@ -89,7 +101,7 @@ namespace Content.Shared.Construction
|
|||||||
/// Uses breadth first search for pathfinding.
|
/// Uses breadth first search for pathfinding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="start"></param>
|
/// <param name="start"></param>
|
||||||
private Dictionary<ConstructionGraphNode, ConstructionGraphNode> Pathfind(string start)
|
private Dictionary<ConstructionGraphNode, ConstructionGraphNode> PathsForStart(string start)
|
||||||
{
|
{
|
||||||
// TODO: Make this use A* or something, although it's not that important.
|
// TODO: Make this use A* or something, although it's not that important.
|
||||||
var startNode = _nodes[start];
|
var startNode = _nodes[start];
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ namespace Content.Shared.GameObjects.Verbs
|
|||||||
("Debug", "/Textures/Interface/VerbIcons/debug.svg.96dpi.png");
|
("Debug", "/Textures/Interface/VerbIcons/debug.svg.96dpi.png");
|
||||||
|
|
||||||
public static readonly VerbCategoryData Rotate = ("Rotate", null);
|
public static readonly VerbCategoryData Rotate = ("Rotate", null);
|
||||||
|
public static readonly VerbCategoryData Construction = ("Construction", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,6 +250,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorControlBox
|
graph: particleAcceleratorControlBox
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ParticleAcceleratorBase
|
parent: ParticleAcceleratorBase
|
||||||
@@ -266,6 +267,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorEmitterLeft
|
graph: particleAcceleratorEmitterLeft
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ParticleAcceleratorBase
|
parent: ParticleAcceleratorBase
|
||||||
@@ -282,6 +284,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorEmitterCenter
|
graph: particleAcceleratorEmitterCenter
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ParticleAcceleratorBase
|
parent: ParticleAcceleratorBase
|
||||||
@@ -298,6 +301,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorEmitterRight
|
graph: particleAcceleratorEmitterRight
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ParticleAcceleratorBase
|
parent: ParticleAcceleratorBase
|
||||||
@@ -314,6 +318,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorEndCap
|
graph: particleAcceleratorEndCap
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ParticleAcceleratorBase
|
parent: ParticleAcceleratorBase
|
||||||
@@ -330,6 +335,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorFuelChamber
|
graph: particleAcceleratorFuelChamber
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ParticleAcceleratorBase
|
parent: ParticleAcceleratorBase
|
||||||
@@ -346,3 +352,5 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: particleAcceleratorPowerBox
|
graph: particleAcceleratorPowerBox
|
||||||
node: start
|
node: start
|
||||||
|
defaultTarget: completed
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user