SharedLatheSystem.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. using System.Diagnostics.CodeAnalysis;
  2. using System.Linq;
  3. using Content.Shared.Emag.Systems;
  4. using Content.Shared.Examine;
  5. using Content.Shared.Lathe.Prototypes;
  6. using Content.Shared.Localizations;
  7. using Content.Shared.Materials;
  8. using Content.Shared.Research.Prototypes;
  9. using JetBrains.Annotations;
  10. using Robust.Shared.Prototypes;
  11. using Robust.Shared.Utility;
  12. namespace Content.Shared.Lathe;
  13. /// <summary>
  14. /// This handles...
  15. /// </summary>
  16. public abstract class SharedLatheSystem : EntitySystem
  17. {
  18. [Dependency] private readonly IPrototypeManager _proto = default!;
  19. [Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;
  20. [Dependency] private readonly EmagSystem _emag = default!;
  21. public readonly Dictionary<string, List<LatheRecipePrototype>> InverseRecipes = new();
  22. public override void Initialize()
  23. {
  24. base.Initialize();
  25. SubscribeLocalEvent<EmagLatheRecipesComponent, GotEmaggedEvent>(OnEmagged);
  26. SubscribeLocalEvent<LatheComponent, ExaminedEvent>(OnExamined);
  27. SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
  28. BuildInverseRecipeDictionary();
  29. }
  30. /// <summary>
  31. /// Add every recipe in the list of recipe packs to a single hashset.
  32. /// </summary>
  33. public void AddRecipesFromPacks(HashSet<ProtoId<LatheRecipePrototype>> recipes, IEnumerable<ProtoId<LatheRecipePackPrototype>> packs)
  34. {
  35. foreach (var id in packs)
  36. {
  37. var pack = _proto.Index(id);
  38. recipes.UnionWith(pack.Recipes);
  39. }
  40. }
  41. private void OnExamined(Entity<LatheComponent> ent, ref ExaminedEvent args)
  42. {
  43. if (!args.IsInDetailsRange)
  44. return;
  45. if (ent.Comp.ReagentOutputSlotId != null)
  46. args.PushMarkup(Loc.GetString("lathe-menu-reagent-slot-examine"));
  47. }
  48. [PublicAPI]
  49. public bool CanProduce(EntityUid uid, string recipe, int amount = 1, LatheComponent? component = null)
  50. {
  51. return _proto.TryIndex<LatheRecipePrototype>(recipe, out var proto) && CanProduce(uid, proto, amount, component);
  52. }
  53. public bool CanProduce(EntityUid uid, LatheRecipePrototype recipe, int amount = 1, LatheComponent? component = null)
  54. {
  55. if (!Resolve(uid, ref component))
  56. return false;
  57. if (!HasRecipe(uid, recipe, component))
  58. return false;
  59. foreach (var (material, needed) in recipe.Materials)
  60. {
  61. var adjustedAmount = AdjustMaterial(needed, recipe.ApplyMaterialDiscount, component.MaterialUseMultiplier);
  62. if (_materialStorage.GetMaterialAmount(uid, material) < adjustedAmount * amount)
  63. return false;
  64. }
  65. return true;
  66. }
  67. private void OnEmagged(EntityUid uid, EmagLatheRecipesComponent component, ref GotEmaggedEvent args)
  68. {
  69. if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
  70. return;
  71. if (_emag.CheckFlag(uid, EmagType.Interaction))
  72. return;
  73. args.Handled = true;
  74. }
  75. public static int AdjustMaterial(int original, bool reduce, float multiplier)
  76. => reduce ? (int) MathF.Ceiling(original * multiplier) : original;
  77. protected abstract bool HasRecipe(EntityUid uid, LatheRecipePrototype recipe, LatheComponent component);
  78. private void OnPrototypesReloaded(PrototypesReloadedEventArgs obj)
  79. {
  80. if (!obj.WasModified<LatheRecipePrototype>())
  81. return;
  82. BuildInverseRecipeDictionary();
  83. }
  84. private void BuildInverseRecipeDictionary()
  85. {
  86. InverseRecipes.Clear();
  87. foreach (var latheRecipe in _proto.EnumeratePrototypes<LatheRecipePrototype>())
  88. {
  89. if (latheRecipe.Result is not {} result)
  90. continue;
  91. InverseRecipes.GetOrNew(result).Add(latheRecipe);
  92. }
  93. }
  94. public bool TryGetRecipesFromEntity(string prototype, [NotNullWhen(true)] out List<LatheRecipePrototype>? recipes)
  95. {
  96. recipes = new();
  97. if (InverseRecipes.TryGetValue(prototype, out var r))
  98. recipes.AddRange(r);
  99. return recipes.Count != 0;
  100. }
  101. public string GetRecipeName(ProtoId<LatheRecipePrototype> proto)
  102. {
  103. return GetRecipeName(_proto.Index(proto));
  104. }
  105. public string GetRecipeName(LatheRecipePrototype proto)
  106. {
  107. if (!string.IsNullOrWhiteSpace(proto.Name))
  108. return Loc.GetString(proto.Name);
  109. if (proto.Result is {} result)
  110. {
  111. return _proto.Index(result).Name;
  112. }
  113. if (proto.ResultReagents is { } resultReagents)
  114. {
  115. return ContentLocalizationManager.FormatList(resultReagents
  116. .Select(p => Loc.GetString("lathe-menu-result-reagent-display", ("reagent", _proto.Index(p.Key).LocalizedName), ("amount", p.Value)))
  117. .ToList());
  118. }
  119. return string.Empty;
  120. }
  121. [PublicAPI]
  122. public string GetRecipeDescription(ProtoId<LatheRecipePrototype> proto)
  123. {
  124. return GetRecipeDescription(_proto.Index(proto));
  125. }
  126. public string GetRecipeDescription(LatheRecipePrototype proto)
  127. {
  128. if (!string.IsNullOrWhiteSpace(proto.Description))
  129. return Loc.GetString(proto.Description);
  130. if (proto.Result is {} result)
  131. {
  132. return _proto.Index(result).Description;
  133. }
  134. if (proto.ResultReagents is { } resultReagents)
  135. {
  136. // We only use the first one for the description since these descriptions don't combine very well.
  137. var reagent = resultReagents.First().Key;
  138. return _proto.Index(reagent).LocalizedDescription;
  139. }
  140. return string.Empty;
  141. }
  142. }