From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Date: Fri, 2 May 2025 08:37:14 +0000 (-0400)
Subject: Add condition support to entity tables (#36819)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=26ebf06b8170b1d4c14c0c94c9bea87f407e3235;p=space-station-14.git
Add condition support to entity tables (#36819)
---
diff --git a/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs b/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs
new file mode 100644
index 0000000000..9505b6502c
--- /dev/null
+++ b/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs
@@ -0,0 +1,28 @@
+using Content.Shared.EntityTable.EntitySelectors;
+using JetBrains.Annotations;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityTable.Conditions;
+
+///
+/// Used for implementing conditional logic for .
+///
+[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
+public abstract partial class EntityTableCondition
+{
+ ///
+ /// If true, inverts the result of the condition.
+ ///
+ [DataField]
+ public bool Invert;
+
+ public bool Evaluate(IEntityManager entMan, IPrototypeManager proto)
+ {
+ var res = EvaluateImplementation(entMan, proto);
+
+ // XOR eval to invert the result.
+ return res ^ Invert;
+ }
+
+ public abstract bool EvaluateImplementation(IEntityManager entMan, IPrototypeManager proto);
+}
diff --git a/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs b/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs
new file mode 100644
index 0000000000..72ac75ca3f
--- /dev/null
+++ b/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs
@@ -0,0 +1,34 @@
+using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityTable.Conditions;
+
+///
+/// Condition that passes only if the server player count is within a certain range.
+///
+public sealed partial class PlayerCountCondition : EntityTableCondition
+{
+ ///
+ /// Minimum players of needed for this condition to succeed. Inclusive.
+ ///
+ [DataField]
+ public int Min = int.MinValue;
+
+ ///
+ /// Maximum numbers of players there can be for this condition to succeed. Inclusive.
+ ///
+ [DataField]
+ public int Max = int.MaxValue;
+
+ private static ISharedPlayerManager? _playerManager;
+
+ public override bool EvaluateImplementation(IEntityManager entMan, IPrototypeManager proto)
+ {
+ // Don't resolve this repeatedly
+ _playerManager ??= IoCManager.Resolve();
+
+ var playerCount = _playerManager.PlayerCount;
+
+ return playerCount >= Min && playerCount <= Max;
+ }
+}
diff --git a/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs b/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs
index d0a7a4d578..6ad80c4a2a 100644
--- a/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs
@@ -1,3 +1,4 @@
+using Content.Shared.EntityTable.Conditions;
using Content.Shared.EntityTable.ValueSelector;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
@@ -26,10 +27,26 @@ public abstract partial class EntityTableSelector
[DataField]
public double Prob = 1;
+ ///
+ /// A list of conditions that must evaluate to 'true' for the selector to apply.
+ ///
+ [DataField]
+ public List Conditions = new();
+
+ ///
+ /// If true, all the conditions must be successful in order for the selector to process.
+ /// Otherwise, only one of them must be.
+ ///
+ [DataField]
+ public bool RequireAll = true;
+
public IEnumerable GetSpawns(System.Random rand,
IEntityManager entMan,
IPrototypeManager proto)
{
+ if (!CheckConditions(entMan, proto))
+ yield break;
+
var rolls = Rolls.Get(rand);
for (var i = 0; i < rolls; i++)
{
@@ -43,6 +60,28 @@ public abstract partial class EntityTableSelector
}
}
+ public bool CheckConditions(IEntityManager entMan, IPrototypeManager proto)
+ {
+ if (Conditions.Count == 0)
+ return true;
+
+ var success = false;
+ foreach (var condition in Conditions)
+ {
+ var res = condition.Evaluate(entMan, proto);
+
+ if (RequireAll && !res)
+ return false; // intentional break out of loop and function
+
+ success |= res;
+ }
+
+ if (RequireAll)
+ return true;
+
+ return success;
+ }
+
protected abstract IEnumerable GetSpawnsImplementation(System.Random rand,
IEntityManager entMan,
IPrototypeManager proto);
diff --git a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs
index 8f761f9866..8012eeae68 100644
--- a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs
+++ b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs
@@ -18,6 +18,10 @@ public sealed partial class GroupSelector : EntityTableSelector
var children = new Dictionary(Children.Count);
foreach (var child in Children)
{
+ // Don't include invalid groups
+ if (!child.CheckConditions(entMan, proto))
+ continue;
+
children.Add(child, child.Weight);
}
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
index 6770680b63..05c362ac6a 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
@@ -51,6 +51,10 @@
- id: SpaceCash1000
- id: WeaponDisabler
- id: ClothingEyesGlassesCommand
+ - id: HeadSkeleton # A skull to accompany your skeleton crew
+ conditions:
+ - !type:PlayerCountCondition
+ max: 15
# No laser table + Laser table
- type: entityTable