using System.Threading;
using System.Threading.Tasks;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Damage;
using Content.Shared.Emag.Components;
using Content.Shared.Interaction;
using Content.Shared.Silicons.Bots;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
public sealed partial class PickNearbyWeldableOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private EntityLookupSystem _lookup = default!;
private WeldbotSystem _weldbot = default!;
private PathfindingSystem _pathfinding = default!;
private TagSystem _tagSystem = default!;
[DataField] public string RangeKey = NPCBlackboard.WeldbotWeldRange;
///
/// Target entity to weld
///
[DataField(required: true)]
public string TargetKey = string.Empty;
///
/// Target entitycoordinates to move to.
///
[DataField(required: true)]
public string TargetMoveKey = string.Empty;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem();
_weldbot = sysManager.GetEntitySystem();
_pathfinding = sysManager.GetEntitySystem();
_tagSystem = sysManager.GetEntitySystem();
}
public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var owner = blackboard.GetValue(NPCBlackboard.Owner);
if (!blackboard.TryGetValue(RangeKey, out var range, _entManager) || !_entManager.TryGetComponent(owner, out var weldbot))
return (false, null);
var damageQuery = _entManager.GetEntityQuery();
var emagged = _entManager.HasComponent(owner);
foreach (var target in _lookup.GetEntitiesInRange(owner, range))
{
if (!damageQuery.TryGetComponent(target, out var damage))
continue;
var tagSiliconMobPrototype = _prototypeManager.Index(WeldbotWeldOperator.SiliconTag);
var tagWeldFixableStructurePrototype = _prototypeManager.Index(WeldbotWeldOperator.WeldotFixableStructureTag);
if (!_entManager.TryGetComponent(target, out var tagComponent))
continue;
var canWeldSiliconMob = _tagSystem.HasTag(tagComponent, tagSiliconMobPrototype) && (emagged || damage.DamagePerGroup["Brute"].Value > 0);
var canWeldStructure = _tagSystem.HasTag(tagComponent, tagWeldFixableStructurePrototype) && damage.TotalDamage.Value > 0;
if(!canWeldSiliconMob && !canWeldStructure)
continue;
var pathRange = SharedInteractionSystem.InteractionRange;
//Needed to make sure it doesn't sometimes stop right outside its interaction range, in case of a mob.
if (canWeldSiliconMob)
pathRange--;
var path = await _pathfinding.GetPath(owner, target, pathRange, cancelToken);
if (path.Result == PathResult.NoPath)
continue;
return (true, new Dictionary()
{
{TargetKey, target},
{TargetMoveKey, _entManager.GetComponent(target).Coordinates},
{NPCBlackboard.PathfindKey, path},
});
}
return (false, null);
}
}