From: āda Date: Wed, 15 Oct 2025 23:48:00 +0000 (-0500) Subject: Grenade penguin htn (#34935) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=b84931dd390f29e388dbf496922ddedf9be50b87;p=space-station-14.git Grenade penguin htn (#34935) * we can do better * better * slightlybetter * remove unused dependency * uplink description more descriptive * more intentional explosion stats * cleanup --------- Co-authored-by: iaada Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- diff --git a/Content.Server/NPC/HTN/Preconditions/InFriendlyContainerPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/InFriendlyContainerPrecondition.cs new file mode 100644 index 0000000000..ffee9adaf3 --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/InFriendlyContainerPrecondition.cs @@ -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; + +/// +/// Checks if the owner is in a friendly container. +/// Recursively checks if container's container is friendly. +/// +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(); + _npcFaction = sysManager.GetEntitySystem(); + } + + public override bool IsMet(NPCBlackboard blackboard) + { + var owner = blackboard.GetValue(NPCBlackboard.Owner); + + if (!_container.TryGetContainingContainer(owner, out var container)) + return !IsInFriendlyContainer; + + return IsInFriendlyContainer == IsContainerOrParentFriendly(owner, container.Owner); + } + + /// + /// Recursively check if a container or any parent container is friendly. + /// + /// True if any container is friendly. + 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); + } +} diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index c7a697fa6f..7ae8ddd4f9 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -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. diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index ebe8134d1b..7c28e36c11 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -2346,7 +2346,7 @@ - type: MobMover - type: HTN rootTask: - task: SimpleHostileCompound + task: GrenadePenguinCompound - type: NpcFactionMember factions: - Syndicate @@ -2394,9 +2394,9 @@ beepInterval: 1 - type: Explosive explosionType: Default - maxIntensity: 20 - intensitySlope: 20 - totalIntensity: 225 + maxIntensity: 10 + intensitySlope: 3 + totalIntensity: 150 - type: ExplodeOnTrigger keysIn: - timer diff --git a/Resources/Prototypes/NPCs/Combat/melee.yml b/Resources/Prototypes/NPCs/Combat/melee.yml index 9cbfbe7ca0..e25284bb88 100644 --- a/Resources/Prototypes/NPCs/Combat/melee.yml +++ b/Resources/Prototypes/NPCs/Combat/melee.yml @@ -178,3 +178,13 @@ 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 index 0000000000..9665ab342d --- /dev/null +++ b/Resources/Prototypes/NPCs/grenadepenguin.yml @@ -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