diff --git a/Content.Server/Store/Conditions/BuyerSpeciesCondition.cs b/Content.Server/Store/Conditions/BuyerSpeciesCondition.cs new file mode 100644 index 0000000000..bf676704f4 --- /dev/null +++ b/Content.Server/Store/Conditions/BuyerSpeciesCondition.cs @@ -0,0 +1,47 @@ +using Content.Shared.Store; +using Content.Shared.Species; +using Content.Shared.CharacterAppearance.Components; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; + +namespace Content.Server.Store.Conditions; + +/// +/// Allows a store entry to be filtered out based on the user's species. +/// Supports both blacklists and whitelists. +/// +public sealed class BuyerSpeciesCondition : ListingCondition +{ + /// + /// A whitelist of species that can purchase this listing. + /// + [DataField("whitelist", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] + public HashSet? Whitelist; + + /// + /// A blacklist of species that cannot purchase this listing. + /// + [DataField("blacklist", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] + public HashSet? Blacklist; + + public override bool Condition(ListingConditionArgs args) + { + var ent = args.EntityManager; + + if (!ent.TryGetComponent(args.Buyer, out var appearance) || appearance.Species == null) + return true; // inanimate or non-humanoid entities should be handled elsewhere, main example being surplus crates + + if (Blacklist != null) + { + if (Blacklist.Contains(appearance.Species)) + return false; + } + + if (Whitelist != null) + { + if (!Whitelist.Contains(appearance.Species)) + return false; + } + + return true; + } +}