ReactionPrototype.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using Content.Shared.Chemistry.Reagent;
  2. using Content.Shared.Database;
  3. using Content.Shared.EntityEffects;
  4. using Content.Shared.FixedPoint;
  5. using Robust.Shared.Audio;
  6. using Robust.Shared.Prototypes;
  7. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
  8. namespace Content.Shared.Chemistry.Reaction
  9. {
  10. /// <summary>
  11. /// Prototype for chemical reaction definitions
  12. /// </summary>
  13. [Prototype]
  14. public sealed partial class ReactionPrototype : IPrototype, IComparable<ReactionPrototype>
  15. {
  16. [ViewVariables]
  17. [IdDataField]
  18. public string ID { get; private set; } = default!;
  19. [DataField("name")]
  20. public string Name { get; private set; } = string.Empty;
  21. /// <summary>
  22. /// Reactants required for the reaction to occur.
  23. /// </summary>
  24. [DataField("reactants", customTypeSerializer:typeof(PrototypeIdDictionarySerializer<ReactantPrototype, ReagentPrototype>))]
  25. public Dictionary<string, ReactantPrototype> Reactants = new();
  26. /// <summary>
  27. /// The minimum temperature the reaction can occur at.
  28. /// </summary>
  29. [DataField("minTemp")]
  30. public float MinimumTemperature = 0.0f;
  31. /// <summary>
  32. /// If true, this reaction will attempt to conserve thermal energy.
  33. /// </summary>
  34. [DataField("conserveEnergy")]
  35. public bool ConserveEnergy = true;
  36. /// <summary>
  37. /// The maximum temperature the reaction can occur at.
  38. /// </summary>
  39. [DataField("maxTemp")]
  40. public float MaximumTemperature = float.PositiveInfinity;
  41. /// <summary>
  42. /// The required mixing categories for an entity to mix the solution with for the reaction to occur
  43. /// </summary>
  44. [DataField("requiredMixerCategories")]
  45. public List<ProtoId<MixingCategoryPrototype>>? MixingCategories;
  46. /// <summary>
  47. /// Reagents created when the reaction occurs.
  48. /// </summary>
  49. [DataField("products", customTypeSerializer:typeof(PrototypeIdDictionarySerializer<FixedPoint2, ReagentPrototype>))]
  50. public Dictionary<string, FixedPoint2> Products = new();
  51. /// <summary>
  52. /// Effects to be triggered when the reaction occurs.
  53. /// </summary>
  54. [DataField("effects", serverOnly: true)] public List<EntityEffect> Effects = new();
  55. /// <summary>
  56. /// How dangerous is this effect? Stuff like bicaridine should be low, while things like methamphetamine
  57. /// or potas/water should be high.
  58. /// </summary>
  59. [DataField("impact", serverOnly: true)] public LogImpact Impact = LogImpact.Low;
  60. // TODO SERV3: Empty on the client, (de)serialize on the server with module manager is server module
  61. [DataField("sound", serverOnly: true)] public SoundSpecifier Sound { get; private set; } = new SoundPathSpecifier("/Audio/Effects/Chemistry/bubbles.ogg");
  62. /// <summary>
  63. /// If true, this reaction will only consume only integer multiples of the reactant amounts. If there are not
  64. /// enough reactants, the reaction does not occur. Useful for spawn-entity reactions (e.g. creating cheese).
  65. /// </summary>
  66. [DataField("quantized")] public bool Quantized = false;
  67. /// <summary>
  68. /// Determines the order in which reactions occur. This should used to ensure that (in general) descriptive /
  69. /// pop-up generating and explosive reactions occur before things like foam/area effects.
  70. /// </summary>
  71. [DataField("priority")]
  72. public int Priority;
  73. /// <summary>
  74. /// Determines whether or not this reaction creates a new chemical (false) or if it's a breakdown for existing chemicals (true)
  75. /// Used in the chemistry guidebook to make divisions between recipes and reaction sources.
  76. /// </summary>
  77. /// <example>
  78. /// Mixing together two reagents to get a third -> false
  79. /// Heating a reagent to break it down into 2 different ones -> true
  80. /// </example>
  81. [DataField]
  82. public bool Source;
  83. /// <summary>
  84. /// Comparison for creating a sorted set of reactions. Determines the order in which reactions occur.
  85. /// </summary>
  86. public int CompareTo(ReactionPrototype? other)
  87. {
  88. if (other == null)
  89. return -1;
  90. if (Priority != other.Priority)
  91. return other.Priority - Priority;
  92. // Prioritize reagents that don't generate products. This should reduce instances where a solution
  93. // temporarily overflows and discards products simply due to the order in which the reactions occurred.
  94. // Basically: Make space in the beaker before adding new products.
  95. if (Products.Count != other.Products.Count)
  96. return Products.Count - other.Products.Count;
  97. return string.Compare(ID, other.ID, StringComparison.Ordinal);
  98. }
  99. }
  100. /// <summary>
  101. /// Prototype for chemical reaction reactants.
  102. /// </summary>
  103. [DataDefinition]
  104. public sealed partial class ReactantPrototype
  105. {
  106. [DataField("amount")]
  107. private FixedPoint2 _amount = FixedPoint2.New(1);
  108. [DataField("catalyst")]
  109. private bool _catalyst;
  110. /// <summary>
  111. /// Minimum amount of the reactant needed for the reaction to occur.
  112. /// </summary>
  113. public FixedPoint2 Amount => _amount;
  114. /// <summary>
  115. /// Whether or not the reactant is a catalyst. Catalysts aren't removed when a reaction occurs.
  116. /// </summary>
  117. public bool Catalyst => _catalyst;
  118. }
  119. }