--- /dev/null
+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);
+ }
+}
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.
- 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
id: MeleeService
proto: OrderedTargets
key: Target
+
+- type: htnCompound
+ id: DoNotEscapeCompound
+ branches:
+ - preconditions:
+ - !type:InFriendlyContainerPrecondition
+ isInFriendlyContainer: true
+ tasks:
+ - !type:HTNPrimitiveTask
+ operator: !type:NoOperator
--- /dev/null
+- 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