From 31491775e597fe9906df66d7285d5b63ba92daa2 Mon Sep 17 00:00:00 2001
From: Tornado Tech <54727692+Tornado-Technology@users.noreply.github.com>
Date: Wed, 8 May 2024 19:18:03 +1000
Subject: [PATCH] Added new HTN operations and preconditions (#27486)
* Added new HTN operations & preconditions
* Ok I forgot about partial
* Namespace pierce the skies
* Some fixes, debug and new operators
* Bruh git eat my files
---
.../HTN/Preconditions/GunAmmoPrecondition.cs | 2 +-
.../Preconditions/KeyNotExistsPrecondition.cs | 12 +++
.../Math/KeyBoolEqualsPrecondition.cs | 23 +++++
.../Math/KeyFloatEqualsPrecondition.cs | 18 ++++
.../Math/KeyFloatGreaterPrecondition.cs | 17 ++++
.../Math/KeyFloatLessPrecondition.cs | 17 ++++
.../Operators/Math/AddFloatOperator.cs | 33 +++++++
.../Operators/Math/SetBoolOperator.cs | 28 ++++++
.../Operators/{ => Math}/SetFloatOperator.cs | 18 ++--
.../Operators/Math/SetRandomFloatOperator.cs | 34 +++++++
.../Operators/PlaySoundOperator.cs | 28 ++++++
.../Operators/SayKeyOperator.cs | 36 ++++++++
.../Entities/Mobs/Debugging/debug_counter.yml | 53 +++++++++++
Resources/Prototypes/NPCs/debug.yml | 90 +++++++++++++++++++
14 files changed, 401 insertions(+), 8 deletions(-)
create mode 100644 Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs
create mode 100644 Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs
create mode 100644 Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs
create mode 100644 Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs
create mode 100644 Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs
create mode 100644 Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs
create mode 100644 Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs
rename Content.Server/NPC/HTN/PrimitiveTasks/Operators/{ => Math}/SetFloatOperator.cs (52%)
create mode 100644 Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs
create mode 100644 Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs
create mode 100644 Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs
create mode 100644 Resources/Prototypes/Entities/Mobs/Debugging/debug_counter.yml
create mode 100644 Resources/Prototypes/NPCs/debug.yml
diff --git a/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs
index fe3b844ae3..58647d8874 100644
--- a/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs
+++ b/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs
@@ -35,7 +35,7 @@ public sealed partial class GunAmmoPrecondition : HTNPrecondition
else
percent = ammoEv.Count / (float) ammoEv.Capacity;
- percent = Math.Clamp(percent, 0f, 1f);
+ percent = System.Math.Clamp(percent, 0f, 1f);
if (MaxPercent < percent)
return false;
diff --git a/Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs
new file mode 100644
index 0000000000..c12663901c
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs
@@ -0,0 +1,12 @@
+namespace Content.Server.NPC.HTN.Preconditions;
+
+public sealed partial class KeyNotExistsPrecondition : HTNPrecondition
+{
+ [DataField(required: true)]
+ public string Key = string.Empty;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ return !blackboard.ContainsKey(Key);
+ }
+}
diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs
new file mode 100644
index 0000000000..8c7920e8be
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs
@@ -0,0 +1,23 @@
+namespace Content.Server.NPC.HTN.Preconditions.Math;
+
+///
+/// Checks for the presence of data in the blackboard and makes a comparison with the specified boolean
+///
+public sealed partial class KeyBoolEqualsPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public string Key = string.Empty;
+
+ [DataField(required: true)]
+ public bool Value;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ if (!blackboard.TryGetValue(Key, out var value, _entManager))
+ return false;
+
+ return Value == value;
+ }
+}
diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs
new file mode 100644
index 0000000000..802fdaf2b9
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs
@@ -0,0 +1,18 @@
+namespace Content.Server.NPC.HTN.Preconditions.Math;
+
+public sealed partial class KeyFloatEqualsPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public string Key = string.Empty;
+
+ [DataField(required: true)]
+ public float Value;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ return blackboard.TryGetValue(Key, out var value, _entManager) &&
+ MathHelper.CloseTo(value, value);
+ }
+}
diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs
new file mode 100644
index 0000000000..3a9ac36698
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs
@@ -0,0 +1,17 @@
+namespace Content.Server.NPC.HTN.Preconditions.Math;
+
+public sealed partial class KeyFloatGreaterPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public string Key = string.Empty;
+
+ [DataField(required: true)]
+ public float Value;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ return blackboard.TryGetValue(Key, out var value, _entManager) && value > Value;
+ }
+}
diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs
new file mode 100644
index 0000000000..5cd51d7a7c
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs
@@ -0,0 +1,17 @@
+namespace Content.Server.NPC.HTN.Preconditions.Math;
+
+public sealed partial class KeyFloatLessPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public string Key = string.Empty;
+
+ [DataField(required: true)]
+ public float Value;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ return blackboard.TryGetValue(Key, out var value, _entManager) && value < Value;
+ }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs
new file mode 100644
index 0000000000..00404517c9
--- /dev/null
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs
@@ -0,0 +1,33 @@
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
+
+///
+/// Gets the key, and adds the value to that float
+///
+public sealed partial class AddFloatOperator : HTNOperator
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField(required: true)]
+ public string TargetKey = string.Empty;
+
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float Amount;
+
+ public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
+ CancellationToken cancelToken)
+ {
+ if (!blackboard.TryGetValue(TargetKey, out var value, _entManager))
+ return (false, null);
+
+ return (
+ true,
+ new Dictionary
+ {
+ { TargetKey, value + Amount }
+ }
+ );
+ }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs
new file mode 100644
index 0000000000..a40b96798d
--- /dev/null
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs
@@ -0,0 +1,28 @@
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
+
+///
+/// Just sets a blackboard key to a bool
+///
+public sealed partial class SetBoolOperator : HTNOperator
+{
+ [DataField(required: true)]
+ public string TargetKey = string.Empty;
+
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool Value;
+
+ public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
+ CancellationToken cancelToken)
+ {
+ return (
+ true,
+ new Dictionary
+ {
+ { TargetKey, Value }
+ }
+ );
+ }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SetFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetFloatOperator.cs
similarity index 52%
rename from Content.Server/NPC/HTN/PrimitiveTasks/Operators/SetFloatOperator.cs
rename to Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetFloatOperator.cs
index 7a460592cb..76842b431f 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SetFloatOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetFloatOperator.cs
@@ -1,24 +1,28 @@
using System.Threading;
using System.Threading.Tasks;
-namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
///
/// Just sets a blackboard key to a float
///
public sealed partial class SetFloatOperator : HTNOperator
{
- [DataField("targetKey", required: true)] public string TargetKey = string.Empty;
+ [DataField(required: true)]
+ public string TargetKey = string.Empty;
- [ViewVariables(VVAccess.ReadWrite), DataField("amount")]
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
public float Amount;
public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
- return (true, new Dictionary()
- {
- {TargetKey, Amount},
- });
+ return (
+ true,
+ new Dictionary
+ {
+ { TargetKey, Amount }
+ }
+ );
}
}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs
new file mode 100644
index 0000000000..999756f1f7
--- /dev/null
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs
@@ -0,0 +1,34 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Robust.Shared.Random;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
+
+///
+/// Sets a random float from MinAmount to MaxAmount to blackboard
+///
+public sealed partial class SetRandomFloatOperator : HTNOperator
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ [DataField(required: true)]
+ public string TargetKey = string.Empty;
+
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float MaxAmount = 1f;
+
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float MinAmount = 0f;
+
+ public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
+ CancellationToken cancelToken)
+ {
+ return (
+ true,
+ new Dictionary
+ {
+ { TargetKey, _random.NextFloat(MinAmount, MaxAmount) }
+ }
+ );
+ }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs
new file mode 100644
index 0000000000..57cc2e91e4
--- /dev/null
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs
@@ -0,0 +1,28 @@
+using Robust.Server.Audio;
+using Robust.Shared.Audio;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
+
+public sealed partial class PlaySoundOperator : HTNOperator
+{
+ private AudioSystem _audio = default!;
+
+ [DataField(required: true)]
+ public SoundSpecifier? Sound;
+
+ public override void Initialize(IEntitySystemManager sysManager)
+ {
+ base.Initialize(sysManager);
+
+ _audio = IoCManager.Resolve().GetEntitySystem();
+ }
+
+ public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+ {
+ var uid = blackboard.GetValue(NPCBlackboard.Owner);
+
+ _audio.PlayPvs(Sound, uid);
+
+ return base.Update(blackboard, frameTime);
+ }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs
new file mode 100644
index 0000000000..d1c7d61915
--- /dev/null
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs
@@ -0,0 +1,36 @@
+using Content.Server.Chat.Systems;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
+
+public sealed partial class SayKeyOperator : HTNOperator
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ private ChatSystem _chat = default!;
+
+ [DataField(required: true)]
+ public string Key = string.Empty;
+
+ ///
+ /// Whether to hide message from chat window and logs.
+ ///
+ [DataField]
+ public bool Hidden;
+
+ public override void Initialize(IEntitySystemManager sysManager)
+ {
+ base.Initialize(sysManager);
+ _chat = IoCManager.Resolve().GetEntitySystem();
+ }
+
+ public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+ {
+ if (!blackboard.TryGetValue