using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.EntityEffects; using Content.Shared.FixedPoint; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Shared.Chemistry.Reaction { /// /// Prototype for chemical reaction definitions /// [Prototype] public sealed partial class ReactionPrototype : IPrototype, IComparable { [ViewVariables] [IdDataField] public string ID { get; private set; } = default!; [DataField("name")] public string Name { get; private set; } = string.Empty; /// /// Reactants required for the reaction to occur. /// [DataField("reactants", customTypeSerializer:typeof(PrototypeIdDictionarySerializer))] public Dictionary Reactants = new(); /// /// The minimum temperature the reaction can occur at. /// [DataField("minTemp")] public float MinimumTemperature = 0.0f; /// /// If true, this reaction will attempt to conserve thermal energy. /// [DataField("conserveEnergy")] public bool ConserveEnergy = true; /// /// The maximum temperature the reaction can occur at. /// [DataField("maxTemp")] public float MaximumTemperature = float.PositiveInfinity; /// /// The required mixing categories for an entity to mix the solution with for the reaction to occur /// [DataField("requiredMixerCategories")] public List>? MixingCategories; /// /// Reagents created when the reaction occurs. /// [DataField("products", customTypeSerializer:typeof(PrototypeIdDictionarySerializer))] public Dictionary Products = new(); /// /// Effects to be triggered when the reaction occurs. /// [DataField("effects", serverOnly: true)] public List Effects = new(); /// /// How dangerous is this effect? Stuff like bicaridine should be low, while things like methamphetamine /// or potas/water should be high. /// [DataField("impact", serverOnly: true)] public LogImpact Impact = LogImpact.Low; // TODO SERV3: Empty on the client, (de)serialize on the server with module manager is server module [DataField("sound", serverOnly: true)] public SoundSpecifier Sound { get; private set; } = new SoundPathSpecifier("/Audio/Effects/Chemistry/bubbles.ogg"); /// /// If true, this reaction will only consume only integer multiples of the reactant amounts. If there are not /// enough reactants, the reaction does not occur. Useful for spawn-entity reactions (e.g. creating cheese). /// [DataField("quantized")] public bool Quantized = false; /// /// Determines the order in which reactions occur. This should used to ensure that (in general) descriptive / /// pop-up generating and explosive reactions occur before things like foam/area effects. /// [DataField("priority")] public int Priority; /// /// Determines whether or not this reaction creates a new chemical (false) or if it's a breakdown for existing chemicals (true) /// Used in the chemistry guidebook to make divisions between recipes and reaction sources. /// /// /// Mixing together two reagents to get a third -> false /// Heating a reagent to break it down into 2 different ones -> true /// [DataField] public bool Source; /// /// Comparison for creating a sorted set of reactions. Determines the order in which reactions occur. /// public int CompareTo(ReactionPrototype? other) { if (other == null) return -1; if (Priority != other.Priority) return other.Priority - Priority; // Prioritize reagents that don't generate products. This should reduce instances where a solution // temporarily overflows and discards products simply due to the order in which the reactions occurred. // Basically: Make space in the beaker before adding new products. if (Products.Count != other.Products.Count) return Products.Count - other.Products.Count; return string.Compare(ID, other.ID, StringComparison.Ordinal); } } /// /// Prototype for chemical reaction reactants. /// [DataDefinition] public sealed partial class ReactantPrototype { [DataField("amount")] private FixedPoint2 _amount = FixedPoint2.New(1); [DataField("catalyst")] private bool _catalyst; /// /// Minimum amount of the reactant needed for the reaction to occur. /// public FixedPoint2 Amount => _amount; /// /// Whether or not the reactant is a catalyst. Catalysts aren't removed when a reaction occurs. /// public bool Catalyst => _catalyst; } }