using Content.Shared.Atmos.Components;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Popups;
using Content.Shared.SubFloor;
using Content.Shared.Tools;
using Content.Shared.Tools.Components;
using Content.Shared.Tools.Systems;
using Content.Shared.Verbs;
using Robust.Shared.Prototypes;
using System.Diagnostics.CodeAnalysis;
namespace Content.Shared.Atmos.EntitySystems;
///
/// The system responsible for checking and adjusting the connection layering of gas pipes
///
public abstract partial class SharedAtmosPipeLayersSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly SharedToolSystem _tool = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnExamined);
SubscribeLocalEvent>(OnGetVerb);
SubscribeLocalEvent(OnInteractUsing);
SubscribeLocalEvent(OnUseInHandEvent);
SubscribeLocalEvent(OnSetNextPipeLayerCompleted);
SubscribeLocalEvent(OnSettingPipeLayerCompleted);
}
private void OnExamined(Entity ent, ref ExaminedEvent args)
{
var layerName = GetPipeLayerName(ent.Comp.CurrentPipeLayer);
args.PushMarkup(Loc.GetString("atmos-pipe-layers-component-current-layer", ("layerName", layerName)));
}
private void OnGetVerb(Entity ent, ref GetVerbsEvent args)
{
if (!args.CanAccess || !args.CanInteract || !args.CanComplexInteract)
return;
if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked)
return;
if (!_protoManager.TryIndex(ent.Comp.Tool, out var toolProto))
return;
var user = args.User;
if (TryComp(ent, out var subFloorHide) && subFloorHide.IsUnderCover)
{
var v = new Verb
{
Priority = 1,
Category = VerbCategory.Adjust,
Text = Loc.GetString("atmos-pipe-layers-component-pipes-are-covered"),
Disabled = true,
Impact = LogImpact.Low,
DoContactInteraction = true,
};
args.Verbs.Add(v);
}
else if (!TryGetHeldTool(user, ent.Comp.Tool, out var tool))
{
var v = new Verb
{
Priority = 1,
Category = VerbCategory.Adjust,
Text = Loc.GetString("atmos-pipe-layers-component-tool-missing", ("toolName", Loc.GetString(toolProto.ToolName).ToLower())),
Disabled = true,
Impact = LogImpact.Low,
DoContactInteraction = true,
};
args.Verbs.Add(v);
}
else
{
for (var i = 0; i < ent.Comp.NumberOfPipeLayers; i++)
{
var index = i;
var layerName = GetPipeLayerName((AtmosPipeLayer)index);
var label = Loc.GetString("atmos-pipe-layers-component-select-layer", ("layerName", layerName));
var v = new Verb
{
Priority = 1,
Category = VerbCategory.Adjust,
Text = label,
Disabled = index == (int)ent.Comp.CurrentPipeLayer,
Impact = LogImpact.Low,
DoContactInteraction = true,
Act = () =>
{
_tool.UseTool(tool.Value, user, ent, ent.Comp.Delay, tool.Value.Comp.Qualities, new TrySettingPipeLayerCompletedEvent((AtmosPipeLayer)index));
}
};
args.Verbs.Add(v);
}
}
}
private void OnInteractUsing(Entity ent, ref InteractUsingEvent args)
{
if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked)
return;
if (!TryComp(args.Used, out var tool) || !_tool.HasQuality(args.Used, ent.Comp.Tool, tool))
return;
if (TryComp(ent, out var subFloorHide) && subFloorHide.IsUnderCover)
{
_popup.PopupClient(Loc.GetString("atmos-pipe-layers-component-cannot-adjust-pipes"), ent, args.User);
return;
}
_tool.UseTool(args.Used, args.User, ent, ent.Comp.Delay, tool.Qualities, new TrySetNextPipeLayerCompletedEvent());
}
private void OnUseInHandEvent(Entity ent, ref UseInHandEvent args)
{
if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked)
return;
if (!TryGetHeldTool(args.User, ent.Comp.Tool, out var tool))
{
if (_protoManager.TryIndex(ent.Comp.Tool, out var toolProto))
{
var toolName = Loc.GetString(toolProto.ToolName).ToLower();
var message = Loc.GetString("atmos-pipe-layers-component-tool-missing", ("toolName", toolName));
_popup.PopupClient(message, ent, args.User);
}
return;
}
_tool.UseTool(tool.Value, args.User, ent, ent.Comp.Delay, tool.Value.Comp.Qualities, new TrySetNextPipeLayerCompletedEvent());
}
private void OnSetNextPipeLayerCompleted(Entity ent, ref TrySetNextPipeLayerCompletedEvent args)
{
if (args.Cancelled)
return;
SetNextPipeLayer(ent, args.User, args.Used);
}
private void OnSettingPipeLayerCompleted(Entity ent, ref TrySettingPipeLayerCompletedEvent args)
{
if (args.Cancelled)
return;
SetPipeLayer(ent, args.PipeLayer, args.User, args.Used);
}
///
/// Increments an entity's pipe layer by 1, wrapping around to 0 if the max pipe layer is reached
///
/// The pipe entity
/// The player entity who adjusting the pipe layer
/// The tool used to adjust the pipe layer
public void SetNextPipeLayer(Entity ent, EntityUid? user = null, EntityUid? used = null)
{
var newLayer = ((int)ent.Comp.CurrentPipeLayer + 1) % ent.Comp.NumberOfPipeLayers;
SetPipeLayer(ent, (AtmosPipeLayer)newLayer, user, used);
}
///
/// Sets an entity's pipe layer to a specified value
///
/// The pipe entity
/// The new layer value
/// The player entity who adjusting the pipe layer
/// The tool used to adjust the pipe layer
public virtual void SetPipeLayer(Entity ent, AtmosPipeLayer layer, EntityUid? user = null, EntityUid? used = null)
{
if (ent.Comp.PipeLayersLocked)
return;
ent.Comp.CurrentPipeLayer = (AtmosPipeLayer)Math.Clamp((int)layer, 0, ent.Comp.NumberOfPipeLayers - 1);
Dirty(ent);
if (TryComp(ent, out var appearance))
{
if (ent.Comp.SpriteRsiPaths.TryGetValue(ent.Comp.CurrentPipeLayer, out var path))
_appearance.SetData(ent, AtmosPipeLayerVisuals.Sprite, path, appearance);
if (ent.Comp.SpriteLayersRsiPaths.Count > 0)
{
var data = new Dictionary();
foreach (var (layerKey, rsiPaths) in ent.Comp.SpriteLayersRsiPaths)
{
if (rsiPaths.TryGetValue(ent.Comp.CurrentPipeLayer, out path))
data.TryAdd(layerKey, path);
}
_appearance.SetData(ent, AtmosPipeLayerVisuals.SpriteLayers, data, appearance);
}
}
if (user != null)
{
var layerName = GetPipeLayerName(ent.Comp.CurrentPipeLayer);
var message = Loc.GetString("atmos-pipe-layers-component-change-layer", ("layerName", layerName));
_popup.PopupClient(message, ent, user);
}
}
///
/// Try to find an entity prototype associated with a specified .
///
/// The with the alternative prototypes data.
/// The atmos pipe layer associated with the entity prototype.
/// The returned entity prototype.
/// True if there was an entity prototype associated with the layer.
public bool TryGetAlternativePrototype(AtmosPipeLayersComponent component, AtmosPipeLayer layer, out EntProtoId proto)
{
return component.AlternativePrototypes.TryGetValue(layer, out proto);
}
///
/// Checks a player entity's hands to see if they are holding a tool with a specified quality
///
/// The player entity
/// The tool quality being checked for
/// A tool with the specified tool quality
/// True if an appropriate tool was found
private bool TryGetHeldTool(EntityUid user, ProtoId toolQuality, [NotNullWhen(true)] out Entity? heldTool)
{
heldTool = null;
foreach (var heldItem in _hands.EnumerateHeld(user))
{
if (TryComp(heldItem, out var tool) &&
_tool.HasQuality(heldItem, toolQuality, tool))
{
heldTool = new Entity(heldItem, tool);
return true;
}
}
return false;
}
private string GetPipeLayerName(AtmosPipeLayer layer)
{
return Loc.GetString("atmos-pipe-layers-component-layer-" + layer.ToString().ToLower());
}
}