using Content.Server.Construction.Components;
using Content.Server.DoAfter;
using Content.Server.Stack;
using Content.Server.Tools;
using Content.Shared.Construction;
using Content.Shared.Examine;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Construction
{
///
/// The server-side implementation of the construction system, which is used for constructing entities in game.
///
[UsedImplicitly]
public partial class ConstructionSystem : SharedConstructionSystem
{
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly StackSystem _stackSystem = default!;
[Dependency] private readonly ToolSystem _toolSystem = default!;
private const string SawmillName = "Construction";
private ISawmill _sawmill = default!;
public override void Initialize()
{
base.Initialize();
_sawmill = _logManager.GetSawmill(SawmillName);
InitializeGraphs();
InitializeSteps();
InitializeInitial();
SubscribeLocalEvent(OnConstructionInit);
SubscribeLocalEvent(OnConstructionStartup);
SubscribeLocalEvent(AddDeconstructVerb);
SubscribeLocalEvent(HandleConstructionExamined);
}
private void OnConstructionInit(EntityUid uid, ConstructionComponent construction, ComponentInit args)
{
if (GetCurrentGraph(uid, construction) is not {} graph)
{
_sawmill.Warning($"Prototype {construction.Owner.Prototype?.ID}'s construction component has an invalid graph specified.");
return;
}
if (GetNodeFromGraph(graph, construction.Node) is not {} node)
{
_sawmill.Warning($"Prototype {construction.Owner.Prototype?.ID}'s construction component has an invalid node specified.");
return;
}
ConstructionGraphEdge? edge = null;
if (construction.EdgeIndex is {} edgeIndex)
{
if (GetEdgeFromNode(node, edgeIndex) is not {} currentEdge)
{
_sawmill.Warning($"Prototype {construction.Owner.Prototype?.ID}'s construction component has an invalid edge index specified.");
return;
}
edge = currentEdge;
}
if (construction.TargetNode is {} targetNodeId)
{
if (GetNodeFromGraph(graph, targetNodeId) is not { } targetNode)
{
_sawmill.Warning($"Prototype {construction.Owner.Prototype?.ID}'s construction component has an invalid target node specified.");
return;
}
UpdatePathfinding(uid, graph, node, targetNode, edge, construction);
}
}
private void OnConstructionStartup(EntityUid uid, ConstructionComponent construction, ComponentStartup args)
{
if (GetCurrentNode(uid, construction) is not {} node)
return;
PerformActions(uid, null, node.Actions);
}
private void AddDeconstructVerb(EntityUid uid, ConstructionComponent component, GetOtherVerbsEvent args)
{
if (!args.CanAccess)
return;
if (component.TargetNode == component.DeconstructionNode ||
component.Node == component.DeconstructionNode)
return;
Verb verb = new();
//verb.Category = VerbCategories.Construction;
//TODO VERBS add more construction verbs? Until then, removing construction category
verb.Text = Loc.GetString("deconstructible-verb-begin-deconstruct");
verb.IconTexture = "/Textures/Interface/hammer_scaled.svg.192dpi.png";
verb.Act = () =>
{
SetPathfindingTarget(uid, component.DeconstructionNode, component);
if (component.TargetNode == 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(args.User, Loc.GetString("deconstructible-verb-activate-no-target-text"));
}
else
{
component.Owner.PopupMessage(args.User, Loc.GetString("deconstructible-verb-activate-text"));
}
};
args.Verbs.Add(verb);
}
private void HandleConstructionExamined(EntityUid uid, ConstructionComponent component, ExaminedEvent args)
{
if (GetTargetNode(uid, component) is {} target)
{
args.PushMarkup(Loc.GetString(
"construction-component-to-create-header",
("targetName", target.Name)) + "\n");
}
if (component.EdgeIndex == null && GetTargetEdge(uid, component) is {} targetEdge)
{
var preventStepExamine = false;
foreach (var condition in targetEdge.Conditions)
{
preventStepExamine |= condition.DoExamine(args);
}
if (!preventStepExamine)
targetEdge.Steps[0].DoExamine(args);
return;
}
if (GetCurrentEdge(uid, component) is {} edge)
{
var preventStepExamine = false;
foreach (var condition in edge.Conditions)
{
preventStepExamine |= condition.DoExamine(args);
}
if (preventStepExamine) return;
}
}
public override void Update(float frameTime)
{
base.Update(frameTime);
UpdateInteractions();
}
}
}