ReactiveSystem.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using Content.Shared.Administration.Logs;
  2. using Content.Shared.Chemistry.Components;
  3. using Content.Shared.Chemistry.Reaction;
  4. using Content.Shared.Chemistry.Reagent;
  5. using Content.Shared.Database;
  6. using Content.Shared.EntityEffects;
  7. using JetBrains.Annotations;
  8. using Robust.Shared.Prototypes;
  9. using Robust.Shared.Random;
  10. namespace Content.Shared.Chemistry;
  11. [UsedImplicitly]
  12. public sealed class ReactiveSystem : EntitySystem
  13. {
  14. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  15. [Dependency] private readonly IRobustRandom _robustRandom = default!;
  16. [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
  17. public void DoEntityReaction(EntityUid uid, Solution solution, ReactionMethod method)
  18. {
  19. foreach (var reagent in solution.Contents.ToArray())
  20. {
  21. ReactionEntity(uid, method, reagent, solution);
  22. }
  23. }
  24. public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentQuantity reagentQuantity, Solution? source)
  25. {
  26. // We throw if the reagent specified doesn't exist.
  27. var proto = _prototypeManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
  28. ReactionEntity(uid, method, proto, reagentQuantity, source);
  29. }
  30. public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype proto,
  31. ReagentQuantity reagentQuantity, Solution? source)
  32. {
  33. if (!TryComp(uid, out ReactiveComponent? reactive))
  34. return;
  35. // If we have a source solution, use the reagent quantity we have left. Otherwise, use the reaction volume specified.
  36. var args = new EntityEffectReagentArgs(uid, EntityManager, null, source, source?.GetReagentQuantity(reagentQuantity.Reagent) ?? reagentQuantity.Quantity, proto, method, 1f);
  37. // First, check if the reagent wants to apply any effects.
  38. if (proto.ReactiveEffects != null && reactive.ReactiveGroups != null)
  39. {
  40. foreach (var (key, val) in proto.ReactiveEffects)
  41. {
  42. if (!val.Methods.Contains(method))
  43. continue;
  44. if (!reactive.ReactiveGroups.ContainsKey(key))
  45. continue;
  46. if (!reactive.ReactiveGroups[key].Contains(method))
  47. continue;
  48. foreach (var effect in val.Effects)
  49. {
  50. if (!effect.ShouldApply(args, _robustRandom))
  51. continue;
  52. if (effect.ShouldLog)
  53. {
  54. var entity = args.TargetEntity;
  55. _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
  56. $"Reactive effect {effect.GetType().Name:effect} of reagent {proto.ID:reagent} with method {method} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}");
  57. }
  58. effect.Effect(args);
  59. }
  60. }
  61. }
  62. // Then, check if the prototype has any effects it can apply as well.
  63. if (reactive.Reactions != null)
  64. {
  65. foreach (var entry in reactive.Reactions)
  66. {
  67. if (!entry.Methods.Contains(method))
  68. continue;
  69. if (entry.Reagents != null && !entry.Reagents.Contains(proto.ID))
  70. continue;
  71. foreach (var effect in entry.Effects)
  72. {
  73. if (!effect.ShouldApply(args, _robustRandom))
  74. continue;
  75. if (effect.ShouldLog)
  76. {
  77. var entity = args.TargetEntity;
  78. _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
  79. $"Reactive effect {effect.GetType().Name:effect} of {ToPrettyString(entity):entity} using reagent {proto.ID:reagent} with method {method} at {Transform(entity).Coordinates:coordinates}");
  80. }
  81. effect.Effect(args);
  82. }
  83. }
  84. }
  85. }
  86. }
  87. public enum ReactionMethod
  88. {
  89. Touch,
  90. Injection,
  91. Ingestion,
  92. }