Files
wwdpublic/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyWeldableOperator.cs
Timfa 4df010f255 Allow Weldbot to Fix Specific Structures (#1838)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
As requested in Goobstation MRP;

This update allows the weldbot to, _very slowly_, fix specific
structures.
To allow a structure to be repaired by a weldbot, apply the
"WeldbotFixableStructure" tag to it.
So far, this has been applied to:
- Windows
- Directional Windows
- Grounding Rods
- Tesla Coils
The robot will repair 5 damage per step to structures. In addition,
repair speeds of silicon mobs, borgs and IPC's has been lowered a bit.

---

# Changelog

<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

🆑
- tweak: Weldbots can now fix specific structures, like windows and
grounding rods.

---------

Signed-off-by: Timfa <timfalken@hotmail.com>
(cherry picked from commit a7760a6ee17766b4724382e0f4ed1698eaf19444)
2025-02-28 16:27:40 +03:00

95 lines
3.7 KiB
C#

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;
/// <summary>
/// Target entity to weld
/// </summary>
[DataField(required: true)]
public string TargetKey = string.Empty;
/// <summary>
/// Target entitycoordinates to move to.
/// </summary>
[DataField(required: true)]
public string TargetMoveKey = string.Empty;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem<EntityLookupSystem>();
_weldbot = sysManager.GetEntitySystem<WeldbotSystem>();
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
_tagSystem = sysManager.GetEntitySystem<TagSystem>();
}
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (!blackboard.TryGetValue<float>(RangeKey, out var range, _entManager) || !_entManager.TryGetComponent<WeldbotComponent>(owner, out var weldbot))
return (false, null);
var damageQuery = _entManager.GetEntityQuery<DamageableComponent>();
var emagged = _entManager.HasComponent<EmaggedComponent>(owner);
foreach (var target in _lookup.GetEntitiesInRange(owner, range))
{
if (!damageQuery.TryGetComponent(target, out var damage))
continue;
var tagSiliconMobPrototype = _prototypeManager.Index<TagPrototype>(WeldbotWeldOperator.SiliconTag);
var tagWeldFixableStructurePrototype = _prototypeManager.Index<TagPrototype>(WeldbotWeldOperator.WeldotFixableStructureTag);
if (!_entManager.TryGetComponent<TagComponent>(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<string, object>()
{
{TargetKey, target},
{TargetMoveKey, _entManager.GetComponent<TransformComponent>(target).Coordinates},
{NPCBlackboard.PathfindKey, path},
});
}
return (false, null);
}
}