]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix stupid NPC. (#26868)
authorVigers Ray <60344369+VigersRay@users.noreply.github.com>
Sat, 27 Apr 2024 05:58:09 +0000 (08:58 +0300)
committerGitHub <noreply@github.com>
Sat, 27 Apr 2024 05:58:09 +0000 (15:58 +1000)
* init commit

* Review

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Content.Server/NPC/HTN/Preconditions/InContainerPrecondition.cs [new file with mode: 0644]
Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/ContainerOperator.cs [new file with mode: 0644]
Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/EscapeOperator.cs [new file with mode: 0644]
Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs [new file with mode: 0644]
Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs [new file with mode: 0644]
Resources/Prototypes/NPCs/Combat/melee.yml

diff --git a/Content.Server/NPC/HTN/Preconditions/InContainerPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/InContainerPrecondition.cs
new file mode 100644 (file)
index 0000000..aa0ad98
--- /dev/null
@@ -0,0 +1,27 @@
+using Robust.Server.Containers;
+
+namespace Content.Server.NPC.HTN.Preconditions;
+
+/// <summary>
+/// Checks if the owner in container or not
+/// </summary>
+public sealed partial class InContainerPrecondition : HTNPrecondition
+{
+    private ContainerSystem _container = default!;
+
+    [ViewVariables(VVAccess.ReadWrite)] [DataField("isInContainer")] public bool IsInContainer = true;
+
+    public override void Initialize(IEntitySystemManager sysManager)
+    {
+        base.Initialize(sysManager);
+        _container = sysManager.GetEntitySystem<ContainerSystem>();
+    }
+
+    public override bool IsMet(NPCBlackboard blackboard)
+    {
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+
+        return IsInContainer && _container.IsEntityInContainer(owner) ||
+               !IsInContainer && !_container.IsEntityInContainer(owner);
+    }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/ContainerOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/ContainerOperator.cs
new file mode 100644 (file)
index 0000000..667d0b8
--- /dev/null
@@ -0,0 +1,40 @@
+using Robust.Server.Containers;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
+
+public sealed partial class ContainerOperator : HTNOperator
+{
+    [Dependency] private readonly IEntityManager _entManager = default!;
+    private ContainerSystem _container = default!;
+    private EntityQuery<TransformComponent> _transformQuery;
+
+    [DataField("shutdownState")]
+    public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
+
+    [DataField("targetKey", required: true)]
+    public string TargetKey = default!;
+
+    public override void Initialize(IEntitySystemManager sysManager)
+    {
+        base.Initialize(sysManager);
+        _container = sysManager.GetEntitySystem<ContainerSystem>();
+        _transformQuery = _entManager.GetEntityQuery<TransformComponent>();
+    }
+
+    public override void Startup(NPCBlackboard blackboard)
+    {
+        base.Startup(blackboard);
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+
+        if (!_container.TryGetOuterContainer(owner, _transformQuery.GetComponent(owner), out var outerContainer) && outerContainer == null)
+            return;
+
+        var target = outerContainer.Owner;
+        blackboard.SetValue(TargetKey, target);
+    }
+
+    public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+    {
+        return HTNOperatorStatus.Finished;
+    }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/EscapeOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/EscapeOperator.cs
new file mode 100644 (file)
index 0000000..a794e1e
--- /dev/null
@@ -0,0 +1,140 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Content.Server.NPC.Components;
+using Content.Server.Storage.EntitySystems;
+using Content.Shared.CombatMode;
+using Robust.Server.Containers;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Melee;
+
+public sealed partial class EscapeOperator : HTNOperator, IHtnConditionalShutdown
+{
+    [Dependency] private readonly IEntityManager _entManager = default!;
+    private ContainerSystem _container = default!;
+    private EntityStorageSystem _entityStorage = default!;
+
+    [DataField("shutdownState")]
+    public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
+
+    [DataField("targetKey", required: true)]
+    public string TargetKey = default!;
+
+    public override void Initialize(IEntitySystemManager sysManager)
+    {
+        base.Initialize(sysManager);
+        _container = sysManager.GetEntitySystem<ContainerSystem>();
+        _entityStorage = sysManager.GetEntitySystem<EntityStorageSystem>();
+    }
+
+    public override void Startup(NPCBlackboard blackboard)
+    {
+        base.Startup(blackboard);
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+        var target = blackboard.GetValue<EntityUid>(TargetKey);
+
+        if (_entityStorage.TryOpenStorage(owner, target))
+        {
+            TaskShutdown(blackboard, HTNOperatorStatus.Finished);
+            return;
+        }
+
+        var melee = _entManager.EnsureComponent<NPCMeleeCombatComponent>(owner);
+        melee.MissChance = blackboard.GetValueOrDefault<float>(NPCBlackboard.MeleeMissChance, _entManager);
+        melee.Target = target;
+    }
+
+    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<EntityUid>(TargetKey, out var target, _entManager))
+        {
+            return (false, null);
+        }
+
+        if (!_container.IsEntityInContainer(owner))
+        {
+            return (false, null);
+        }
+
+        if (_entityStorage.TryOpenStorage(owner, target))
+        {
+            return (false, null);
+        }
+
+        return (true, null);
+    }
+
+    public void ConditionalShutdown(NPCBlackboard blackboard)
+    {
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+        _entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, false);
+        _entManager.RemoveComponent<NPCMeleeCombatComponent>(owner);
+        blackboard.Remove<EntityUid>(TargetKey);
+    }
+
+    public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
+    {
+        base.TaskShutdown(blackboard, status);
+
+        ConditionalShutdown(blackboard);
+    }
+
+    public override void PlanShutdown(NPCBlackboard blackboard)
+    {
+        base.PlanShutdown(blackboard);
+
+        ConditionalShutdown(blackboard);
+    }
+
+    public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+    {
+        base.Update(blackboard, frameTime);
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+        HTNOperatorStatus status;
+
+        if (_entManager.TryGetComponent<NPCMeleeCombatComponent>(owner, out var combat) &&
+            blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
+        {
+            combat.Target = target;
+
+            // Success
+            if (!_container.IsEntityInContainer(owner))
+            {
+                status = HTNOperatorStatus.Finished;
+            }
+            else
+            {
+                if (_entityStorage.TryOpenStorage(owner, target))
+                {
+                    status = HTNOperatorStatus.Finished;
+                }
+                else
+                {
+                    switch (combat.Status)
+                    {
+                        case CombatStatus.TargetOutOfRange:
+                        case CombatStatus.Normal:
+                            status = HTNOperatorStatus.Continuing;
+                            break;
+                        default:
+                            status = HTNOperatorStatus.Failed;
+                            break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            status = HTNOperatorStatus.Failed;
+        }
+
+        // Mark it as finished to continue the plan.
+        if (status == HTNOperatorStatus.Continuing && ShutdownState == HTNPlanState.PlanFinished)
+        {
+            status = HTNOperatorStatus.Finished;
+        }
+
+        return status;
+    }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs
new file mode 100644 (file)
index 0000000..54f422f
--- /dev/null
@@ -0,0 +1,35 @@
+using Content.Shared.Movement.Pulling.Components;
+using Content.Shared.Movement.Pulling.Systems;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
+
+public sealed partial class UnPullOperator : HTNOperator
+{
+    [Dependency] private readonly IEntityManager _entManager = default!;
+    private PullingSystem _pulling = default!;
+
+    private EntityQuery<PullableComponent> _pullableQuery;
+
+    [DataField("shutdownState")]
+    public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
+
+    public override void Initialize(IEntitySystemManager sysManager)
+    {
+        base.Initialize(sysManager);
+        _pulling = sysManager.GetEntitySystem<PullingSystem>();
+        _pullableQuery = _entManager.GetEntityQuery<PullableComponent>();
+    }
+
+    public override void Startup(NPCBlackboard blackboard)
+    {
+        base.Startup(blackboard);
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+
+        _pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner);
+    }
+
+    public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+    {
+        return HTNOperatorStatus.Finished;
+    }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs
new file mode 100644 (file)
index 0000000..207665d
--- /dev/null
@@ -0,0 +1,34 @@
+using Content.Server.Buckle.Systems;
+using Content.Shared.Buckle.Components;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
+
+public sealed partial class UnbuckleOperator : HTNOperator
+{
+    [Dependency] private readonly IEntityManager _entManager = default!;
+    private BuckleSystem _buckle = default!;
+
+    [DataField("shutdownState")]
+    public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
+
+    public override void Initialize(IEntitySystemManager sysManager)
+    {
+        base.Initialize(sysManager);
+        _buckle = sysManager.GetEntitySystem<BuckleSystem>();
+    }
+
+    public override void Startup(NPCBlackboard blackboard)
+    {
+        base.Startup(blackboard);
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+        if (!_entManager.TryGetComponent<BuckleComponent>(owner, out var buckle) || !buckle.Buckled)
+            return;
+
+        _buckle.TryUnbuckle(owner, owner, true, buckle);
+    }
+
+    public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+    {
+        return HTNOperatorStatus.Finished;
+    }
+}
index 122875ed97a9932c40cfe199fa1276c83a808cf3..e4b207d16e068361e502697d7232c3333d7224ae 100644 (file)
         - !type:HTNCompoundTask
           task: PickupMeleeCompound
 
+    - preconditions:
+      - !type:BuckledPrecondition
+        isBuckled: true
+      tasks:
+      - !type:HTNPrimitiveTask
+        shutdownState: TaskFinished
+        operator: !type:UnbuckleOperator
+
+    - preconditions:
+      - !type:InContainerPrecondition
+        isInContainer: true
+      tasks:
+      - !type:HTNCompoundTask
+        task: EscapeCompound
+
+    - preconditions:
+      - !type:PulledPrecondition
+        isPulled: true
+      tasks:
+      - !type:HTNPrimitiveTask
+        shutdownState: TaskFinished
+        operator: !type:UnPullOperator
+
     # Melee combat (unarmed or otherwise)
     - tasks:
         - !type:HTNPrimitiveTask
               proto: NearbyMeleeTargets
               key: Target
 
+- type: htnCompound
+  id: EscapeCompound
+  branches:
+  - tasks:
+    - !type:HTNPrimitiveTask
+      shutdownState: TaskFinished
+      operator: !type:ContainerOperator
+        targetKey: Target
+    - !type:HTNPrimitiveTask
+      operator: !type:EscapeOperator
+        targetKey: Target
+      preconditions:
+      - !type:InContainerPrecondition
+        isInContainer: true
+
 - type: htnCompound
   id: MeleeAttackOrderedTargetCompound
   branches: