]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Grenade penguin htn (#34935)
authorāda <ss.adasts@gmail.com>
Wed, 15 Oct 2025 23:48:00 +0000 (18:48 -0500)
committerGitHub <noreply@github.com>
Wed, 15 Oct 2025 23:48:00 +0000 (23:48 +0000)
* we can do better

* better

* slightlybetter

* remove unused dependency

* uplink description more descriptive

* more intentional explosion stats

* cleanup

---------

Co-authored-by: iaada <iaada@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Content.Server/NPC/HTN/Preconditions/InFriendlyContainerPrecondition.cs [new file with mode: 0644]
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
Resources/Prototypes/NPCs/Combat/melee.yml
Resources/Prototypes/NPCs/grenadepenguin.yml [new file with mode: 0644]

diff --git a/Content.Server/NPC/HTN/Preconditions/InFriendlyContainerPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/InFriendlyContainerPrecondition.cs
new file mode 100644 (file)
index 0000000..ffee9ad
--- /dev/null
@@ -0,0 +1,50 @@
+using Content.Shared.NPC.Systems;
+using Robust.Shared.Containers;
+using Robust.Server.Containers;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.NPC.HTN.Preconditions;
+
+/// <summary>
+/// Checks if the owner is in a friendly container.
+/// Recursively checks if container's container is friendly.
+/// </summary>
+public sealed partial class InFriendlyContainerPrecondition : HTNPrecondition
+{
+    private ContainerSystem _container = default!;
+    private NpcFactionSystem _npcFaction = default!;
+
+    [DataField] public bool IsInFriendlyContainer = true;
+
+    public override void Initialize(IEntitySystemManager sysManager)
+    {
+        base.Initialize(sysManager);
+        _container = sysManager.GetEntitySystem<ContainerSystem>();
+        _npcFaction = sysManager.GetEntitySystem<NpcFactionSystem>();
+    }
+
+    public override bool IsMet(NPCBlackboard blackboard)
+    {
+        var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+
+        if (!_container.TryGetContainingContainer(owner, out var container))
+            return !IsInFriendlyContainer;
+
+        return IsInFriendlyContainer == IsContainerOrParentFriendly(owner, container.Owner);
+    }
+
+    /// <summary>
+    /// Recursively check if a container or any parent container is friendly.
+    /// </summary>
+    /// <returns>True if any container is friendly.</returns>
+    private bool IsContainerOrParentFriendly(EntityUid owner, EntityUid containerOwner)
+    {
+        if (_npcFaction.IsEntityFriendly(owner, containerOwner))
+            return true;
+
+        if (!_container.TryGetContainingContainer(containerOwner, out var nextContainer))
+            return false;
+
+        return IsContainerOrParentFriendly(owner, nextContainer.Owner);
+    }
+}
index c7a697fa6fb3147f41458e95fbed628e2e257862..7ae8ddd4f97bdcb3a490dfad564f0e4c5f5620f8 100644 (file)
@@ -54,7 +54,7 @@ uplink-whitehole-grenade-name = Whitehole Grenade
 uplink-whitehole-grenade-desc = Grenade that repulses everything around for about 10 seconds. Very useful in small rooms and for chasing someone.
 
 uplink-penguin-grenade-name = Grenade Penguin
-uplink-penguin-grenade-desc = A small, highly-aggressive penguin with a grenade strapped around its neck. Harvested by the Syndicate from icy shit-hole planets.
+uplink-penguin-grenade-desc = A small, highly-aggressive penguin with a grenade strapped around its neck. Trained to ignore all Syndicate agents and relentlessly pursue a single, random nearby target when released.
 
 uplink-c4-name = C-4
 uplink-c4-desc = Use it to breach walls, airlocks or sabotage equipment. It can be attached to almost all objects and has a modifiable timer with a minimum setting of 10 seconds.
index ebe8134d1b4e7d3d377777aefdf902bace429c13..7c28e36c11927edd316899079c23d9dbc0d27e91 100644 (file)
   - type: MobMover
   - type: HTN
     rootTask:
-      task: SimpleHostileCompound
+      task: GrenadePenguinCompound
   - type: NpcFactionMember
     factions:
     - Syndicate
     beepInterval: 1
   - type: Explosive
     explosionType: Default
-    maxIntensity: 20
-    intensitySlope: 20
-    totalIntensity: 225
+    maxIntensity: 10
+    intensitySlope: 3
+    totalIntensity: 150
   - type: ExplodeOnTrigger
     keysIn:
     - timer
index 9cbfbe7ca09cdf74314ca3df0d62c2ef6fde5d08..e25284bb8809d2ad976670489c3e009d9b9c178b 100644 (file)
               id: MeleeService
               proto: OrderedTargets
               key: Target
+
+- type: htnCompound
+  id: DoNotEscapeCompound
+  branches:
+  - preconditions:
+    - !type:InFriendlyContainerPrecondition
+      isInFriendlyContainer: true
+    tasks:
+    - !type:HTNPrimitiveTask
+      operator: !type:NoOperator
diff --git a/Resources/Prototypes/NPCs/grenadepenguin.yml b/Resources/Prototypes/NPCs/grenadepenguin.yml
new file mode 100644 (file)
index 0000000..9665ab3
--- /dev/null
@@ -0,0 +1,76 @@
+- type: htnCompound
+  id: GrenadePenguinCompound
+  branches:
+  - tasks:
+    - !type:HTNCompoundTask
+      task: GrenadePenguinMeleeCombatPrecondition
+  - tasks:
+    - !type:HTNCompoundTask
+      task: IdleCompound
+
+- type: htnCompound
+  id: GrenadePenguinMeleeCombatPrecondition
+  branches:
+  - preconditions:
+    - !type:BuckledPrecondition
+      isBuckled: true
+    tasks:
+    - !type:HTNPrimitiveTask
+      operator: !type:UnbuckleOperator
+        shutdownState: TaskFinished
+
+  - preconditions:
+    - !type:InFriendlyContainerPrecondition
+      isInFriendlyContainer: true
+    tasks:
+    - !type:HTNCompoundTask
+      task: DoNotEscapeCompound
+
+  - preconditions:
+    - !type:InContainerPrecondition
+      isInContainer: true
+    tasks:
+    - !type:HTNCompoundTask
+      task: EscapeCompound
+
+  - preconditions:
+    - !type:PulledPrecondition
+      isPulled: true
+    tasks:
+    - !type:HTNPrimitiveTask
+      operator: !type:UnPullOperator
+        shutdownState: TaskFinished
+
+  - tasks:
+    - !type:HTNPrimitiveTask
+      operator: !type:UtilityOperator
+        proto: NearbyMeleeTargets
+    - !type:HTNCompoundTask
+      task: GrenadePenguinMeleeCombatCompound
+
+- type: htnCompound
+  id: GrenadePenguinMeleeCombatCompound
+  branches:
+  - preconditions:
+    - !type:KeyExistsPrecondition
+      key: Target
+    tasks:
+    - !type:HTNPrimitiveTask
+      operator: !type:MoveToOperator
+        shutdownState: PlanFinished
+        pathfindInPlanning: true
+        removeKeyOnFinish: false
+        targetKey: TargetCoordinates
+        pathfindKey: TargetPathfind
+        rangeKey: MeleeRange
+    # too angry to juke
+    - !type:HTNPrimitiveTask
+      operator: !type:MeleeOperator
+        targetKey: Target
+      preconditions:
+      - !type:KeyExistsPrecondition
+        key: Target
+      - !type:TargetInRangePrecondition
+        targetKey: Target
+        rangeKey: MeleeRange
+    # no service, no changing target