BotanySystem.Seed.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using Content.Server.Botany.Components;
  2. using Content.Server.Kitchen.Components;
  3. using Content.Server.Popups;
  4. using Content.Shared.Chemistry.EntitySystems;
  5. using Content.Shared.Botany;
  6. using Content.Shared.Examine;
  7. using Content.Shared.Hands.EntitySystems;
  8. using Content.Shared.Popups;
  9. using Content.Shared.Random;
  10. using Content.Shared.Random.Helpers;
  11. using Robust.Server.GameObjects;
  12. using Robust.Shared.Map;
  13. using Robust.Shared.Prototypes;
  14. using Robust.Shared.Random;
  15. using System.Diagnostics.CodeAnalysis;
  16. using System.Linq;
  17. using Content.Shared.Coordinates; // Added for Log
  18. using Robust.Shared.Utility; // Added for FormattedMessage
  19. namespace Content.Server.Botany.Systems;
  20. public sealed partial class BotanySystem : EntitySystem
  21. {
  22. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  23. [Dependency] private readonly IRobustRandom _robustRandom = default!;
  24. [Dependency] private readonly AppearanceSystem _appearance = default!;
  25. [Dependency] private readonly PopupSystem _popupSystem = default!;
  26. [Dependency] private readonly SharedHandsSystem _hands = default!;
  27. [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
  28. [Dependency] private readonly MetaDataSystem _metaData = default!;
  29. [Dependency] private readonly RandomHelperSystem _randomHelper = default!;
  30. public override void Initialize()
  31. {
  32. base.Initialize();
  33. SubscribeLocalEvent<SeedComponent, ExaminedEvent>(OnExamined);
  34. }
  35. public bool TryGetSeed(SeedComponent comp, [NotNullWhen(true)] out SeedData? seed)
  36. {
  37. if (comp.Seed != null)
  38. {
  39. seed = comp.Seed;
  40. return true;
  41. }
  42. if (comp.SeedId != null
  43. && _prototypeManager.TryIndex(comp.SeedId, out SeedPrototype? protoSeed))
  44. {
  45. seed = protoSeed;
  46. return true;
  47. }
  48. seed = null;
  49. return false;
  50. }
  51. public bool TryGetSeed(ProduceComponent comp, [NotNullWhen(true)] out SeedData? seed)
  52. {
  53. if (comp.Seed != null)
  54. {
  55. seed = comp.Seed;
  56. return true;
  57. }
  58. if (comp.SeedId != null
  59. && _prototypeManager.TryIndex(comp.SeedId, out SeedPrototype? protoSeed))
  60. {
  61. seed = protoSeed;
  62. return true;
  63. }
  64. seed = null;
  65. return false;
  66. }
  67. private void OnExamined(EntityUid uid, SeedComponent component, ExaminedEvent args)
  68. {
  69. if (!args.IsInDetailsRange)
  70. return;
  71. if (!TryGetSeed(component, out var seed))
  72. return;
  73. using (args.PushGroup(nameof(SeedComponent), 1))
  74. {
  75. var name = Loc.GetString(seed.DisplayName);
  76. args.PushMarkup(Loc.GetString($"seed-component-description", ("seedName", name)));
  77. args.PushMarkup(Loc.GetString($"seed-component-plant-yield-text", ("seedYield", seed.Yield)));
  78. args.PushMarkup(Loc.GetString($"seed-component-plant-potency-text", ("seedPotency", seed.Potency)));
  79. }
  80. }
  81. #region SeedPrototype prototype stuff
  82. /// <summary>
  83. /// Spawns a new seed packet on the floor at a position, then tries to put it in the user's hands if possible.
  84. /// </summary>
  85. public EntityUid SpawnSeedPacket(SeedData proto, EntityCoordinates coords, EntityUid user, float? healthOverride = null)
  86. {
  87. var seed = Spawn(proto.PacketPrototype, coords);
  88. var seedComp = EnsureComp<SeedComponent>(seed);
  89. seedComp.Seed = proto;
  90. seedComp.HealthOverride = healthOverride;
  91. var name = Loc.GetString(proto.Name);
  92. var noun = Loc.GetString(proto.Noun);
  93. var val = Loc.GetString("botany-seed-packet-name", ("seedName", name), ("seedNoun", noun));
  94. _metaData.SetEntityName(seed, val);
  95. // try to automatically place in user's other hand
  96. _hands.TryPickupAnyHand(user, seed);
  97. return seed;
  98. }
  99. public IEnumerable<EntityUid> AutoHarvest(SeedData proto, EntityCoordinates position, int yieldMod = 1)
  100. {
  101. if (position.IsValid(EntityManager) &&
  102. proto.ProductPrototypes.Count > 0)
  103. return GenerateProduct(proto, position, yieldMod);
  104. return Enumerable.Empty<EntityUid>();
  105. }
  106. public IEnumerable<EntityUid> Harvest(SeedData proto, EntityUid user, int yieldMod = 1)
  107. {
  108. if (proto.ProductPrototypes.Count == 0 || proto.Yield <= 0)
  109. {
  110. _popupSystem.PopupCursor(Loc.GetString("botany-harvest-fail-message"), user, PopupType.Medium);
  111. return Enumerable.Empty<EntityUid>();
  112. }
  113. var name = Loc.GetString(proto.DisplayName);
  114. _popupSystem.PopupCursor(Loc.GetString("botany-harvest-success-message", ("name", name)), user, PopupType.Medium);
  115. return GenerateProduct(proto, Transform(user).Coordinates, yieldMod);
  116. }
  117. public IEnumerable<EntityUid> GenerateProduct(SeedData proto, EntityCoordinates position, int yieldMod = 1)
  118. {
  119. var totalYield = 0;
  120. if (proto.Yield > -1)
  121. {
  122. if (yieldMod < 0)
  123. totalYield = proto.Yield;
  124. else
  125. totalYield = proto.Yield * yieldMod;
  126. totalYield = Math.Max(1, totalYield);
  127. }
  128. var products = new List<EntityUid>();
  129. // If yield is > 1 OR there's more than one product type OR harvest repeats, it's not unique.
  130. if (totalYield > 1 || proto.ProductPrototypes.Count > 1 || proto.HarvestRepeat != HarvestType.NoRepeat)
  131. proto.Unique = false;
  132. for (var i = 0; i < totalYield; i++)
  133. {
  134. // Iterate through ALL product prototypes defined in the seed data
  135. foreach (var productPrototypeId in proto.ProductPrototypes)
  136. {
  137. var entity = Spawn(productPrototypeId, position);
  138. _randomHelper.RandomOffset(entity, 0.25f);
  139. products.Add(entity);
  140. var produce = EnsureComp<ProduceComponent>(entity);
  141. produce.Seed = proto;
  142. ProduceGrown(entity, produce); // Apply specific produce logic (like solutions)
  143. _appearance.SetData(entity, ProduceVisuals.Potency, proto.Potency);
  144. if (proto.Mysterious)
  145. {
  146. var metaData = MetaData(entity);
  147. _metaData.SetEntityName(entity, metaData.EntityName + "?", metaData);
  148. _metaData.SetEntityDescription(entity,
  149. metaData.EntityDescription + " " + Loc.GetString("botany-mysterious-description-addon"), metaData);
  150. }
  151. }
  152. }
  153. return products;
  154. }
  155. public bool CanHarvest(SeedData proto, EntityUid? held = null)
  156. {
  157. return !proto.Ligneous || proto.Ligneous && held != null && HasComp<SharpComponent>(held);
  158. }
  159. #endregion
  160. }