FoodMetamorphRule.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. using Content.Shared.Chemistry.Components.SolutionManager;
  2. using Content.Shared.Chemistry.EntitySystems;
  3. using Content.Shared.Chemistry.Reagent;
  4. using Content.Shared.Destructible.Thresholds;
  5. using Content.Shared.Nutrition.Components;
  6. using Content.Shared.Tag;
  7. using JetBrains.Annotations;
  8. using Robust.Shared.Prototypes;
  9. using Robust.Shared.Serialization;
  10. namespace Content.Shared.Nutrition.FoodMetamorphRules;
  11. /// <summary>
  12. /// abstract rules that are used to verify the correct foodSequence for recipe
  13. /// </summary>
  14. [ImplicitDataDefinitionForInheritors]
  15. [Serializable, NetSerializable]
  16. public abstract partial class FoodMetamorphRule
  17. {
  18. public abstract bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List<FoodSequenceVisualLayer> ingredients);
  19. }
  20. /// <summary>
  21. /// The requirement that the sequence be within the specified size limit
  22. /// </summary>
  23. [UsedImplicitly]
  24. [Serializable, NetSerializable]
  25. public sealed partial class SequenceLength : FoodMetamorphRule
  26. {
  27. [DataField(required: true)]
  28. public MinMax Range;
  29. public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List<FoodSequenceVisualLayer> ingredients)
  30. {
  31. return ingredients.Count <= Range.Max && ingredients.Count >= Range.Min;
  32. }
  33. }
  34. /// <summary>
  35. /// A requirement that the last element of the sequence have one or all of the required tags
  36. /// </summary>
  37. [UsedImplicitly]
  38. [Serializable, NetSerializable]
  39. public sealed partial class LastElementHasTags : FoodMetamorphRule
  40. {
  41. [DataField(required: true)]
  42. public List<ProtoId<TagPrototype>> Tags = new ();
  43. [DataField]
  44. public bool NeedAll = true;
  45. public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List<FoodSequenceVisualLayer> ingredients)
  46. {
  47. var lastIngredient = ingredients[ingredients.Count - 1];
  48. if (!protoMan.TryIndex(lastIngredient.Proto, out var protoIndexed))
  49. return false;
  50. foreach (var tag in Tags)
  51. {
  52. var containsTag = protoIndexed.Tags.Contains(tag);
  53. if (NeedAll && !containsTag)
  54. {
  55. return false;
  56. }
  57. if (!NeedAll && containsTag)
  58. {
  59. return true;
  60. }
  61. }
  62. return NeedAll;
  63. }
  64. }
  65. /// <summary>
  66. /// A requirement that the specified sequence element have one or all of the required tags
  67. /// </summary>
  68. [UsedImplicitly]
  69. [Serializable, NetSerializable]
  70. public sealed partial class ElementHasTags : FoodMetamorphRule
  71. {
  72. [DataField(required: true)]
  73. public int ElementNumber = 0;
  74. [DataField(required: true)]
  75. public List<ProtoId<TagPrototype>> Tags = new ();
  76. [DataField]
  77. public bool NeedAll = true;
  78. public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List<FoodSequenceVisualLayer> ingredients)
  79. {
  80. if (ingredients.Count < ElementNumber + 1)
  81. return false;
  82. if (!protoMan.TryIndex(ingredients[ElementNumber].Proto, out var protoIndexed))
  83. return false;
  84. foreach (var tag in Tags)
  85. {
  86. var containsTag = protoIndexed.Tags.Contains(tag);
  87. if (NeedAll && !containsTag)
  88. {
  89. return false;
  90. }
  91. if (!NeedAll && containsTag)
  92. {
  93. return true;
  94. }
  95. }
  96. return NeedAll;
  97. }
  98. }
  99. /// <summary>
  100. /// requirement that the food contains certain reagents (e.g. sauces)
  101. /// </summary>
  102. [UsedImplicitly]
  103. [Serializable, NetSerializable]
  104. public sealed partial class FoodHasReagent : FoodMetamorphRule
  105. {
  106. [DataField(required: true)]
  107. public ProtoId<ReagentPrototype> Reagent = new();
  108. [DataField(required: true)]
  109. public MinMax Count;
  110. [DataField]
  111. public string Solution = "food";
  112. public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List<FoodSequenceVisualLayer> ingredients)
  113. {
  114. if (!entMan.TryGetComponent<SolutionContainerManagerComponent>(food, out var solMan))
  115. return false;
  116. var solutionMan = entMan.System<SharedSolutionContainerSystem>();
  117. if (!solutionMan.TryGetSolution(food, Solution, out var foodSoln, out var foodSolution))
  118. return false;
  119. foreach (var (id, quantity) in foodSoln.Value.Comp.Solution.Contents)
  120. {
  121. if (id.Prototype != Reagent.Id)
  122. continue;
  123. if (quantity < Count.Min || quantity > Count.Max)
  124. break;
  125. return true;
  126. }
  127. return false;
  128. }
  129. }
  130. /// <summary>
  131. /// A requirement that there be X ingredients in the sequence that have one or all of the specified tags.
  132. /// </summary>
  133. [UsedImplicitly]
  134. [Serializable, NetSerializable]
  135. public sealed partial class IngredientsWithTags : FoodMetamorphRule
  136. {
  137. [DataField(required: true)]
  138. public List<ProtoId<TagPrototype>> Tags = new ();
  139. [DataField(required: true)]
  140. public MinMax Count = new();
  141. [DataField]
  142. public bool NeedAll = true;
  143. public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List<FoodSequenceVisualLayer> ingredients)
  144. {
  145. var count = 0;
  146. foreach (var ingredient in ingredients)
  147. {
  148. if (!protoMan.TryIndex(ingredient.Proto, out var protoIndexed))
  149. continue;
  150. var allowed = false;
  151. if (NeedAll)
  152. {
  153. allowed = true;
  154. foreach (var tag in Tags)
  155. {
  156. if (!protoIndexed.Tags.Contains(tag))
  157. {
  158. allowed = false;
  159. break;
  160. }
  161. }
  162. }
  163. else
  164. {
  165. allowed = false;
  166. foreach (var tag in Tags)
  167. {
  168. if (protoIndexed.Tags.Contains(tag))
  169. {
  170. allowed = true;
  171. break;
  172. }
  173. }
  174. }
  175. if (allowed)
  176. count++;
  177. }
  178. return count >= Count.Min && count <= Count.Max;
  179. }
  180. }