AreaReactionEffect.cs 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using Content.Server.Fluids.EntitySystems;
  2. using Content.Server.Spreader;
  3. using Content.Shared.Audio;
  4. using Content.Shared.Coordinates.Helpers;
  5. using Content.Shared.Database;
  6. using Content.Shared.EntityEffects;
  7. using Content.Shared.FixedPoint;
  8. using Content.Shared.Maps;
  9. using JetBrains.Annotations;
  10. using Robust.Server.GameObjects;
  11. using Robust.Shared.Audio;
  12. using Robust.Shared.Audio.Systems;
  13. using Robust.Shared.Map;
  14. using Robust.Shared.Prototypes;
  15. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
  16. namespace Content.Server.EntityEffects.Effects;
  17. /// <summary>
  18. /// Basically smoke and foam reactions.
  19. /// </summary>
  20. [UsedImplicitly]
  21. [DataDefinition]
  22. public sealed partial class AreaReactionEffect : EntityEffect
  23. {
  24. /// <summary>
  25. /// How many seconds will the effect stay, counting after fully spreading.
  26. /// </summary>
  27. [DataField("duration")] private float _duration = 10;
  28. /// <summary>
  29. /// How many units of reaction for 1 smoke entity.
  30. /// </summary>
  31. [DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
  32. /// <summary>
  33. /// The entity prototype that will be spawned as the effect.
  34. /// </summary>
  35. [DataField("prototypeId", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
  36. private string _prototypeId = default!;
  37. /// <summary>
  38. /// Sound that will get played when this reaction effect occurs.
  39. /// </summary>
  40. [DataField("sound", required: true)] private SoundSpecifier _sound = default!;
  41. public override bool ShouldLog => true;
  42. protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
  43. => Loc.GetString("reagent-effect-guidebook-area-reaction",
  44. ("duration", _duration)
  45. );
  46. public override LogImpact LogImpact => LogImpact.High;
  47. public override void Effect(EntityEffectBaseArgs args)
  48. {
  49. if (args is EntityEffectReagentArgs reagentArgs)
  50. {
  51. if (reagentArgs.Source == null)
  52. return;
  53. var spreadAmount = (int) Math.Max(0, Math.Ceiling((reagentArgs.Quantity / OverflowThreshold).Float()));
  54. var splitSolution = reagentArgs.Source.SplitSolution(reagentArgs.Source.Volume);
  55. var transform = reagentArgs.EntityManager.GetComponent<TransformComponent>(reagentArgs.TargetEntity);
  56. var mapManager = IoCManager.Resolve<IMapManager>();
  57. var mapSys = reagentArgs.EntityManager.System<MapSystem>();
  58. var spreaderSys = args.EntityManager.System<SpreaderSystem>();
  59. var sys = args.EntityManager.System<TransformSystem>();
  60. var mapCoords = sys.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform);
  61. if (!mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
  62. !mapSys.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef))
  63. {
  64. return;
  65. }
  66. if (spreaderSys.RequiresFloorToSpread(_prototypeId) && tileRef.Tile.IsSpace())
  67. return;
  68. var coords = mapSys.MapToGrid(gridUid, mapCoords);
  69. var ent = reagentArgs.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid());
  70. var smoke = reagentArgs.EntityManager.System<SmokeSystem>();
  71. smoke.StartSmoke(ent, splitSolution, _duration, spreadAmount);
  72. var audio = reagentArgs.EntityManager.System<SharedAudioSystem>();
  73. audio.PlayPvs(_sound, reagentArgs.TargetEntity, AudioHelpers.WithVariation(0.125f));
  74. return;
  75. }
  76. // TODO: Someone needs to figure out how to do this for non-reagent effects.
  77. throw new NotImplementedException();
  78. }
  79. }