diff --git a/Content.Server/NPC/HTN/Preconditions/HungryPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/HungryPrecondition.cs
new file mode 100644
index 0000000000..9f0a46b63b
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/HungryPrecondition.cs
@@ -0,0 +1,26 @@
+using Content.Shared.Hands.Components;
+using Content.Shared.Nutrition.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.NPC.HTN.Preconditions;
+
+///
+/// Returns true if the active hand entity has the specified components.
+///
+public sealed partial class HungryPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public HungerThreshold MinHungerState = HungerThreshold.Starving;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ if (!blackboard.TryGetValue(NPCBlackboard.Owner, out var owner, _entManager))
+ {
+ return false;
+ }
+
+ return _entManager.TryGetComponent(owner, out var hunger) ? hunger.CurrentThreshold <= MinHungerState : false;
+ }
+}
diff --git a/Content.Server/NPC/HTN/Preconditions/ThirstyPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/ThirstyPrecondition.cs
new file mode 100644
index 0000000000..97206dc910
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/ThirstyPrecondition.cs
@@ -0,0 +1,26 @@
+using Content.Shared.Hands.Components;
+using Content.Shared.Nutrition.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.NPC.HTN.Preconditions;
+
+///
+/// Returns true if the active hand entity has the specified components.
+///
+public sealed partial class ThirstyPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public ThirstThreshold MinThirstState = ThirstThreshold.Parched;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ if (!blackboard.TryGetValue(NPCBlackboard.Owner, out var owner, _entManager))
+ {
+ return false;
+ }
+
+ return _entManager.TryGetComponent(owner, out var thirst) ? thirst.CurrentThirstThreshold <= MinThirstState : false;
+ }
+}
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index 8f8cb59d5e..74cf35322d 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -1305,7 +1305,17 @@
Dead:
Base: splat-0
- type: Food
+ - type: Thirst
+ startingThirst: 25 # spawn with Okay thirst state
+ thresholds:
+ OverHydrated: 35
+ Okay: 25
+ Thirsty: 15
+ Parched: 10
+ Dead: 0
+ baseDecayRate: 0.04
- type: Hunger
+ currentHunger: 25 # spawn with Okay hunger state
thresholds:
Overfed: 35
Okay: 25
diff --git a/Resources/Prototypes/NPCs/nutrition.yml b/Resources/Prototypes/NPCs/nutrition.yml
index da64989c33..dea065c34f 100644
--- a/Resources/Prototypes/NPCs/nutrition.yml
+++ b/Resources/Prototypes/NPCs/nutrition.yml
@@ -4,6 +4,9 @@
# Picks a nearby food, moves into range, then eats it and waits the idle time.
- tasks:
- !type:HTNPrimitiveTask
+ preconditions:
+ - !type:HungryPrecondition
+ minHungerState: Starving # See HungerThreshold enum
operator: !type:UtilityOperator
proto: NearbyFood
@@ -31,6 +34,9 @@
# Picks nearby drink then consumes it and waits idle time
- tasks:
- !type:HTNPrimitiveTask
+ preconditions:
+ - !type:ThirstyPrecondition
+ minThirstState: Parched # See ThirstThreshold enum
operator: !type:UtilityOperator
proto: NearbyDrink