1
0

AtmosphereSystem.Hotspot.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. using Content.Server.Atmos.Components;
  2. using Content.Server.Decals;
  3. using Content.Shared.Atmos;
  4. using Content.Shared.Atmos.Components;
  5. using Content.Shared.Atmos.Reactions;
  6. using Content.Shared.Database;
  7. using Robust.Shared.Audio;
  8. using Robust.Shared.Map;
  9. using Robust.Shared.Map.Components;
  10. using Robust.Shared.Random;
  11. namespace Content.Server.Atmos.EntitySystems
  12. {
  13. public sealed partial class AtmosphereSystem
  14. {
  15. [Dependency] private readonly DecalSystem _decalSystem = default!;
  16. [Dependency] private readonly IRobustRandom _random = default!;
  17. private const int HotspotSoundCooldownCycles = 200;
  18. private int _hotspotSoundCooldown = 0;
  19. [ViewVariables(VVAccess.ReadWrite)]
  20. public string? HotspotSound { get; private set; } = "/Audio/Effects/fire.ogg";
  21. private void ProcessHotspot(
  22. Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
  23. TileAtmosphere tile)
  24. {
  25. var gridAtmosphere = ent.Comp1;
  26. if (!tile.Hotspot.Valid)
  27. {
  28. gridAtmosphere.HotspotTiles.Remove(tile);
  29. return;
  30. }
  31. AddActiveTile(gridAtmosphere, tile);
  32. if (!tile.Hotspot.SkippedFirstProcess)
  33. {
  34. tile.Hotspot.SkippedFirstProcess = true;
  35. return;
  36. }
  37. if(tile.ExcitedGroup != null)
  38. ExcitedGroupResetCooldowns(tile.ExcitedGroup);
  39. if ((tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist) || (tile.Hotspot.Volume <= 1f)
  40. || tile.Air == null || tile.Air.GetMoles(Gas.Oxygen) < 0.5f || (tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f))
  41. {
  42. tile.Hotspot = new Hotspot();
  43. InvalidateVisuals(ent, tile);
  44. return;
  45. }
  46. PerformHotspotExposure(tile);
  47. if (tile.Hotspot.Bypassing)
  48. {
  49. tile.Hotspot.State = 3;
  50. var gridUid = ent.Owner;
  51. var tilePos = tile.GridIndices;
  52. // Get the existing decals on the tile
  53. var tileDecals = _decalSystem.GetDecalsInRange(gridUid, tilePos);
  54. // Count the burnt decals on the tile
  55. var tileBurntDecals = 0;
  56. foreach (var set in tileDecals)
  57. {
  58. if (Array.IndexOf(_burntDecals, set.Decal.Id) == -1)
  59. continue;
  60. tileBurntDecals++;
  61. if (tileBurntDecals > 4)
  62. break;
  63. }
  64. // Add a random burned decal to the tile only if there are less than 4 of them
  65. if (tileBurntDecals < 4)
  66. _decalSystem.TryAddDecal(_burntDecals[_random.Next(_burntDecals.Length)], new EntityCoordinates(gridUid, tilePos), out _, cleanable: true);
  67. if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread)
  68. {
  69. var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale;
  70. foreach (var otherTile in tile.AdjacentTiles)
  71. {
  72. // TODO ATMOS: This is sus. Suss this out.
  73. if (otherTile == null)
  74. continue;
  75. if(!otherTile.Hotspot.Valid)
  76. HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume/4);
  77. }
  78. }
  79. }
  80. else
  81. {
  82. tile.Hotspot.State = (byte) (tile.Hotspot.Volume > Atmospherics.CellVolume * 0.4f ? 2 : 1);
  83. }
  84. if (tile.Hotspot.Temperature > tile.MaxFireTemperatureSustained)
  85. tile.MaxFireTemperatureSustained = tile.Hotspot.Temperature;
  86. if (_hotspotSoundCooldown++ == 0 && !string.IsNullOrEmpty(HotspotSound))
  87. {
  88. var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices);
  89. // A few details on the audio parameters for fire.
  90. // The greater the fire state, the lesser the pitch variation.
  91. // The greater the fire state, the greater the volume.
  92. _audio.PlayPvs(HotspotSound, coordinates, AudioParams.Default.WithVariation(0.15f/tile.Hotspot.State).WithVolume(-5f + 5f * tile.Hotspot.State));
  93. }
  94. if (_hotspotSoundCooldown > HotspotSoundCooldownCycles)
  95. _hotspotSoundCooldown = 0;
  96. // TODO ATMOS Maybe destroy location here?
  97. }
  98. private void HotspotExpose(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile,
  99. float exposedTemperature, float exposedVolume, bool soh = false, EntityUid? sparkSourceUid = null)
  100. {
  101. if (tile.Air == null)
  102. return;
  103. var oxygen = tile.Air.GetMoles(Gas.Oxygen);
  104. if (oxygen < 0.5f)
  105. return;
  106. var plasma = tile.Air.GetMoles(Gas.Plasma);
  107. var tritium = tile.Air.GetMoles(Gas.Tritium);
  108. if (tile.Hotspot.Valid)
  109. {
  110. if (soh)
  111. {
  112. if (plasma > 0.5f || tritium > 0.5f)
  113. {
  114. if (tile.Hotspot.Temperature < exposedTemperature)
  115. tile.Hotspot.Temperature = exposedTemperature;
  116. if (tile.Hotspot.Volume < exposedVolume)
  117. tile.Hotspot.Volume = exposedVolume;
  118. }
  119. }
  120. return;
  121. }
  122. if ((exposedTemperature > Atmospherics.PlasmaMinimumBurnTemperature) && (plasma > 0.5f || tritium > 0.5f))
  123. {
  124. if (sparkSourceUid.HasValue)
  125. _adminLog.Add(LogType.Flammable, LogImpact.High, $"Heat/spark of {ToPrettyString(sparkSourceUid.Value)} caused atmos ignition of gas: {tile.Air.Temperature.ToString():temperature}K - {oxygen}mol Oxygen, {plasma}mol Plasma, {tritium}mol Tritium");
  126. tile.Hotspot = new Hotspot
  127. {
  128. Volume = exposedVolume * 25f,
  129. Temperature = exposedTemperature,
  130. SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter,
  131. Valid = true,
  132. State = 1
  133. };
  134. AddActiveTile(gridAtmosphere, tile);
  135. gridAtmosphere.HotspotTiles.Add(tile);
  136. }
  137. }
  138. private void PerformHotspotExposure(TileAtmosphere tile)
  139. {
  140. if (tile.Air == null || !tile.Hotspot.Valid) return;
  141. tile.Hotspot.Bypassing = tile.Hotspot.SkippedFirstProcess && tile.Hotspot.Volume > tile.Air.Volume*0.95f;
  142. if (tile.Hotspot.Bypassing)
  143. {
  144. tile.Hotspot.Volume = tile.Air.ReactionResults[(byte)GasReaction.Fire] * Atmospherics.FireGrowthRate;
  145. tile.Hotspot.Temperature = tile.Air.Temperature;
  146. }
  147. else
  148. {
  149. var affected = tile.Air.RemoveVolume(tile.Hotspot.Volume);
  150. affected.Temperature = tile.Hotspot.Temperature;
  151. React(affected, tile);
  152. tile.Hotspot.Temperature = affected.Temperature;
  153. tile.Hotspot.Volume = affected.ReactionResults[(byte)GasReaction.Fire] * Atmospherics.FireGrowthRate;
  154. Merge(tile.Air, affected);
  155. }
  156. var fireEvent = new TileFireEvent(tile.Hotspot.Temperature, tile.Hotspot.Volume);
  157. _entSet.Clear();
  158. _lookup.GetLocalEntitiesIntersecting(tile.GridIndex, tile.GridIndices, _entSet, 0f);
  159. foreach (var entity in _entSet)
  160. {
  161. RaiseLocalEvent(entity, ref fireEvent);
  162. }
  163. }
  164. }
  165. }