1
0

GasLeakRule.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. using Content.Server.Atmos.EntitySystems;
  2. using Content.Server.GameTicking.Rules.Components;
  3. using Content.Server.StationEvents.Components;
  4. using Content.Shared.GameTicking.Components;
  5. using Robust.Shared.Audio;
  6. using Robust.Shared.Random;
  7. using Robust.Shared.Timing;
  8. namespace Content.Server.StationEvents.Events
  9. {
  10. internal sealed class GasLeakRule : StationEventSystem<GasLeakRuleComponent>
  11. {
  12. [Dependency] private readonly IGameTiming _timing = default!;
  13. [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
  14. protected override void Started(EntityUid uid, GasLeakRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
  15. {
  16. base.Started(uid, component, gameRule, args);
  17. if (!TryComp<StationEventComponent>(uid, out var stationEvent))
  18. return;
  19. // Essentially we'll pick out a target amount of gas to leak, then a rate to leak it at, then work out the duration from there.
  20. if (TryFindRandomTile(out component.TargetTile, out var target, out component.TargetGrid, out component.TargetCoords))
  21. {
  22. component.TargetStation = target.Value;
  23. component.FoundTile = true;
  24. component.LeakGas = RobustRandom.Pick(component.LeakableGases);
  25. // Was 50-50 on using normal distribution.
  26. var totalGas = RobustRandom.Next(component.MinimumGas, component.MaximumGas);
  27. component.MolesPerSecond = RobustRandom.Next(component.MinimumMolesPerSecond, component.MaximumMolesPerSecond);
  28. if (gameRule.Delay is {} startAfter)
  29. stationEvent.EndTime = _timing.CurTime + TimeSpan.FromSeconds(totalGas / component.MolesPerSecond + startAfter.Next(RobustRandom));
  30. }
  31. // Look technically if you wanted to guarantee a leak you'd do this in announcement but having the announcement
  32. // there just to fuck with people even if there is no valid tile is funny.
  33. }
  34. protected override void ActiveTick(EntityUid uid, GasLeakRuleComponent component, GameRuleComponent gameRule, float frameTime)
  35. {
  36. base.ActiveTick(uid, component, gameRule, frameTime);
  37. component.TimeUntilLeak -= frameTime;
  38. if (component.TimeUntilLeak > 0f)
  39. return;
  40. component.TimeUntilLeak += component.LeakCooldown;
  41. if (!component.FoundTile ||
  42. component.TargetGrid == default ||
  43. Deleted(component.TargetGrid) ||
  44. !_atmosphere.IsSimulatedGrid(component.TargetGrid))
  45. {
  46. ForceEndSelf(uid, gameRule);
  47. return;
  48. }
  49. var environment = _atmosphere.GetTileMixture(component.TargetGrid, null, component.TargetTile, true);
  50. environment?.AdjustMoles(component.LeakGas, component.LeakCooldown * component.MolesPerSecond);
  51. }
  52. protected override void Ended(EntityUid uid, GasLeakRuleComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
  53. {
  54. base.Ended(uid, component, gameRule, args);
  55. Spark(uid, component);
  56. }
  57. private void Spark(EntityUid uid, GasLeakRuleComponent component)
  58. {
  59. if (RobustRandom.NextFloat() <= component.SparkChance)
  60. {
  61. if (!component.FoundTile ||
  62. component.TargetGrid == default ||
  63. (!Exists(component.TargetGrid) ? EntityLifeStage.Deleted : MetaData(component.TargetGrid).EntityLifeStage) >= EntityLifeStage.Deleted ||
  64. !_atmosphere.IsSimulatedGrid(component.TargetGrid))
  65. {
  66. return;
  67. }
  68. // Don't want it to be so obnoxious as to instantly murder anyone in the area but enough that
  69. // it COULD start potentially start a bigger fire.
  70. _atmosphere.HotspotExpose(component.TargetGrid, component.TargetTile, 700f, 50f, null, true);
  71. Audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/sparks4.ogg"), component.TargetCoords);
  72. }
  73. }
  74. }
  75. }