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); } }