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