ExplosionPrototype.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using Content.Shared.Damage;
  2. using Robust.Shared.Audio;
  3. using Robust.Shared.Prototypes;
  4. using Robust.Shared.Utility;
  5. namespace Content.Shared.Explosion;
  6. /// <summary>
  7. /// Explosion Prototype. Determines damage, tile break probabilities, and visuals.
  8. /// </summary>
  9. /// <remarks>
  10. /// Does not currently support prototype hot-reloading. The explosion-intensity required to destroy airtight
  11. /// entities is evaluated and stored by the explosion system. Adding or removing a prototype would require updating
  12. /// that map of airtight entities. This could be done, but is just not yet implemented.
  13. /// </remarks>
  14. [Prototype]
  15. public sealed partial class ExplosionPrototype : IPrototype
  16. {
  17. [IdDataField]
  18. public string ID { get; private set; } = default!;
  19. /// <summary>
  20. /// Damage to deal to entities. This is scaled by the explosion intensity.
  21. /// </summary>
  22. [DataField("damagePerIntensity", required: true)]
  23. public DamageSpecifier DamagePerIntensity = default!;
  24. /// <summary>
  25. /// Amount of firestacks to apply in addition to igniting.
  26. /// </summary>
  27. [DataField]
  28. public float? FireStacks;
  29. /// <summary>
  30. /// This set of points, together with <see cref="_tileBreakIntensity"/> define a function that maps the
  31. /// explosion intensity to a tile break chance via linear interpolation.
  32. /// </summary>
  33. [DataField("tileBreakChance")]
  34. private float[] _tileBreakChance = { 0f, 1f };
  35. /// <summary>
  36. /// This set of points, together with <see cref="_tileBreakChance"/> define a function that maps the
  37. /// explosion intensity to a tile break chance via linear interpolation.
  38. /// </summary>
  39. [DataField("tileBreakIntensity")]
  40. private float[] _tileBreakIntensity = {0f, 15f };
  41. /// <summary>
  42. /// When a tile is broken by an explosion, the intensity is reduced by this amount and is used to try and
  43. /// break the tile a second time. This is repeated until a roll fails or the tile has become space.
  44. /// </summary>
  45. /// <remarks>
  46. /// If this number is too small, even relatively weak explosions can have a non-zero
  47. /// chance to create a space tile.
  48. /// </remarks>
  49. [DataField("tileBreakRerollReduction")]
  50. public float TileBreakRerollReduction = 10f;
  51. /// <summary>
  52. /// Color emitted by a point light at the center of the explosion.
  53. /// </summary>
  54. [DataField("lightColor")]
  55. public Color LightColor = Color.Orange;
  56. /// <summary>
  57. /// Color used to modulate the fire texture.
  58. /// </summary>
  59. [DataField("fireColor")]
  60. public Color? FireColor;
  61. /// <summary>
  62. /// If an explosion finishes in less than this many iterations, play a small sound instead.
  63. /// </summary>
  64. /// <remarks>
  65. /// This value is tuned such that a minibomb is considered small, but just about anything larger is normal
  66. /// </remarks>
  67. [DataField("smallSoundIterationThreshold")]
  68. public int SmallSoundIterationThreshold = 6;
  69. /// <summary>
  70. /// How far away another explosion in the same tick can be and be combined.
  71. /// Total intensity is added to the original queued explosion.
  72. /// </summary>
  73. [DataField]
  74. public float MaxCombineDistance = 1f;
  75. [DataField("sound")]
  76. public SoundSpecifier Sound = new SoundCollectionSpecifier("Explosion");
  77. [DataField("smallSound")]
  78. public SoundSpecifier SmallSound = new SoundCollectionSpecifier("ExplosionSmall");
  79. [DataField("soundFar")]
  80. public SoundSpecifier SoundFar = new SoundCollectionSpecifier("ExplosionFar", AudioParams.Default.WithVolume(2f));
  81. [DataField("smallSoundFar")]
  82. public SoundSpecifier SmallSoundFar = new SoundCollectionSpecifier("ExplosionSmallFar", AudioParams.Default.WithVolume(2f));
  83. [DataField("texturePath")]
  84. public ResPath TexturePath = new("/Textures/Effects/fire.rsi");
  85. /// <summary>
  86. /// How intense does the explosion have to be at a tile to advance to the next fire texture state?
  87. /// </summary>
  88. [DataField("intensityPerState")]
  89. public float IntensityPerState = 12;
  90. // Theres probably a better way to do this. Currently Atmos just hard codes a constant int, so I have no one to
  91. // steal code from.
  92. [DataField("fireStates")]
  93. public int FireStates = 3;
  94. /// <summary>
  95. /// Basic function for linear interpolation of the _tileBreakChance and _tileBreakIntensity arrays
  96. /// </summary>
  97. public float TileBreakChance(float intensity)
  98. {
  99. if (_tileBreakChance.Length == 0 || _tileBreakChance.Length != _tileBreakIntensity.Length)
  100. {
  101. Logger.Error($"Malformed tile break chance definitions for explosion prototype: {ID}");
  102. return 0;
  103. }
  104. if (intensity >= _tileBreakIntensity[^1] || _tileBreakIntensity.Length == 1)
  105. return _tileBreakChance[^1];
  106. if (intensity <= _tileBreakIntensity[0])
  107. return _tileBreakChance[0];
  108. int i = Array.FindIndex(_tileBreakIntensity, k => k >= intensity);
  109. var slope = (_tileBreakChance[i] - _tileBreakChance[i - 1]) / (_tileBreakIntensity[i] - _tileBreakIntensity[i - 1]);
  110. return _tileBreakChance[i - 1] + slope * (intensity - _tileBreakIntensity[i - 1]);
  111. }
  112. }