Document Atmospherics Hotspot (#41283)
* hotspot partial docs * Finalize docs
This commit is contained in:
@@ -10,198 +10,280 @@ using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems
|
||||
namespace Content.Server.Atmos.EntitySystems;
|
||||
|
||||
public sealed partial class AtmosphereSystem
|
||||
{
|
||||
public sealed partial class AtmosphereSystem
|
||||
/*
|
||||
Handles Hotspots, which are gas-based tile fires that slowly grow and spread
|
||||
to adjacent tiles if conditions are met.
|
||||
|
||||
You can think of a hotspot as a small flame on a tile that
|
||||
grows by consuming a fuel and oxidizer from the tile's air,
|
||||
with a certain volume and temperature.
|
||||
|
||||
This volume grows bigger and bigger as the fire continues,
|
||||
until it effectively engulfs the entire tile, at which point
|
||||
it starts spreading to adjacent tiles by radiating heat.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Collection of hotspot sounds to play.
|
||||
/// </summary>
|
||||
private static readonly ProtoId<SoundCollectionPrototype> DefaultHotspotSounds = "AtmosHotspot";
|
||||
|
||||
[Dependency] private readonly DecalSystem _decalSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Number of cycles the hotspot system must process before it can play another sound
|
||||
/// on a hotspot.
|
||||
/// </summary>
|
||||
private const int HotspotSoundCooldownCycles = 200;
|
||||
|
||||
/// <summary>
|
||||
/// Cooldown counter for hotspot sounds.
|
||||
/// </summary>
|
||||
private int _hotspotSoundCooldown = 0;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SoundSpecifier? HotspotSound = new SoundCollectionSpecifier(DefaultHotspotSounds);
|
||||
|
||||
/// <summary>
|
||||
/// Processes a hotspot on a <see cref="TileAtmosphere"/>.
|
||||
/// </summary>
|
||||
/// <param name="ent">The grid entity that belongs to the tile to process.</param>
|
||||
/// <param name="tile">The <see cref="TileAtmosphere"/> to process.</param>
|
||||
private void ProcessHotspot(
|
||||
Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
|
||||
TileAtmosphere tile)
|
||||
{
|
||||
private static readonly ProtoId<SoundCollectionPrototype> DefaultHotspotSounds = "AtmosHotspot";
|
||||
var gridAtmosphere = ent.Comp1;
|
||||
|
||||
[Dependency] private readonly DecalSystem _decalSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private const int HotspotSoundCooldownCycles = 200;
|
||||
|
||||
private int _hotspotSoundCooldown = 0;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SoundSpecifier? HotspotSound { get; private set; } = new SoundCollectionSpecifier(DefaultHotspotSounds);
|
||||
|
||||
private void ProcessHotspot(
|
||||
Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
|
||||
TileAtmosphere tile)
|
||||
// Hotspots that have fizzled out are assigned a new Hotspot struct
|
||||
// with Valid set to false, so we can just check that here in
|
||||
// one central place instead of manually removing it everywhere.
|
||||
if (!tile.Hotspot.Valid)
|
||||
{
|
||||
var gridAtmosphere = ent.Comp1;
|
||||
if (!tile.Hotspot.Valid)
|
||||
gridAtmosphere.HotspotTiles.Remove(tile);
|
||||
return;
|
||||
}
|
||||
|
||||
AddActiveTile(gridAtmosphere, tile);
|
||||
|
||||
// Prevent the hotspot from processing on the same cycle it was created (???)
|
||||
// TODO ATMOS: Is this even necessary anymore? The queue is kept per processing stage
|
||||
// and is not updated until tne next cycle, so the condition of a hotspot being created
|
||||
// and processed in the same cycle is impossible.
|
||||
if (!tile.Hotspot.SkippedFirstProcess)
|
||||
{
|
||||
tile.Hotspot.SkippedFirstProcess = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tile.ExcitedGroup != null)
|
||||
ExcitedGroupResetCooldowns(tile.ExcitedGroup);
|
||||
|
||||
if (tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist ||
|
||||
tile.Hotspot.Volume <= 1f ||
|
||||
tile.Air == null ||
|
||||
tile.Air.GetMoles(Gas.Oxygen) < 0.5f ||
|
||||
tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f)
|
||||
{
|
||||
tile.Hotspot = new Hotspot();
|
||||
InvalidateVisuals(ent, tile);
|
||||
return;
|
||||
}
|
||||
|
||||
PerformHotspotExposure(tile);
|
||||
|
||||
// This tile has now turned into a full-blown tile-fire.
|
||||
// Start applying fire effects and spreading to adjacent tiles.
|
||||
if (tile.Hotspot.Bypassing)
|
||||
{
|
||||
tile.Hotspot.State = 3;
|
||||
|
||||
var gridUid = ent.Owner;
|
||||
var tilePos = tile.GridIndices;
|
||||
|
||||
// Get the existing decals on the tile
|
||||
var tileDecals = _decalSystem.GetDecalsInRange(gridUid, tilePos);
|
||||
|
||||
// Count the burnt decals on the tile
|
||||
var tileBurntDecals = 0;
|
||||
|
||||
foreach (var set in tileDecals)
|
||||
{
|
||||
gridAtmosphere.HotspotTiles.Remove(tile);
|
||||
return;
|
||||
if (Array.IndexOf(_burntDecals, set.Decal.Id) == -1)
|
||||
continue;
|
||||
|
||||
tileBurntDecals++;
|
||||
|
||||
if (tileBurntDecals > 4)
|
||||
break;
|
||||
}
|
||||
|
||||
AddActiveTile(gridAtmosphere, tile);
|
||||
|
||||
if (!tile.Hotspot.SkippedFirstProcess)
|
||||
// Add a random burned decal to the tile only if there are less than 4 of them
|
||||
if (tileBurntDecals < 4)
|
||||
{
|
||||
tile.Hotspot.SkippedFirstProcess = true;
|
||||
return;
|
||||
_decalSystem.TryAddDecal(_burntDecals[_random.Next(_burntDecals.Length)],
|
||||
new EntityCoordinates(gridUid, tilePos),
|
||||
out _,
|
||||
cleanable: true);
|
||||
}
|
||||
|
||||
if(tile.ExcitedGroup != null)
|
||||
ExcitedGroupResetCooldowns(tile.ExcitedGroup);
|
||||
|
||||
if ((tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist) || (tile.Hotspot.Volume <= 1f)
|
||||
|| tile.Air == null || tile.Air.GetMoles(Gas.Oxygen) < 0.5f || (tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f))
|
||||
if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread)
|
||||
{
|
||||
tile.Hotspot = new Hotspot();
|
||||
InvalidateVisuals(ent, tile);
|
||||
return;
|
||||
}
|
||||
|
||||
PerformHotspotExposure(tile);
|
||||
|
||||
if (tile.Hotspot.Bypassing)
|
||||
{
|
||||
tile.Hotspot.State = 3;
|
||||
|
||||
var gridUid = ent.Owner;
|
||||
var tilePos = tile.GridIndices;
|
||||
|
||||
// Get the existing decals on the tile
|
||||
var tileDecals = _decalSystem.GetDecalsInRange(gridUid, tilePos);
|
||||
|
||||
// Count the burnt decals on the tile
|
||||
var tileBurntDecals = 0;
|
||||
|
||||
foreach (var set in tileDecals)
|
||||
var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale;
|
||||
foreach (var otherTile in tile.AdjacentTiles)
|
||||
{
|
||||
if (Array.IndexOf(_burntDecals, set.Decal.Id) == -1)
|
||||
// TODO ATMOS: This is sus. Suss this out.
|
||||
// Spread this fire to other tiles by exposing them to a hotspot if air can flow there.
|
||||
// Unsure as to why this is sus.
|
||||
if (otherTile == null)
|
||||
continue;
|
||||
|
||||
tileBurntDecals++;
|
||||
|
||||
if (tileBurntDecals > 4)
|
||||
break;
|
||||
if (!otherTile.Hotspot.Valid)
|
||||
HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume / 4);
|
||||
}
|
||||
|
||||
// Add a random burned decal to the tile only if there are less than 4 of them
|
||||
if (tileBurntDecals < 4)
|
||||
_decalSystem.TryAddDecal(_burntDecals[_random.Next(_burntDecals.Length)], new EntityCoordinates(gridUid, tilePos), out _, cleanable: true);
|
||||
|
||||
if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread)
|
||||
{
|
||||
var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale;
|
||||
foreach (var otherTile in tile.AdjacentTiles)
|
||||
{
|
||||
// TODO ATMOS: This is sus. Suss this out.
|
||||
if (otherTile == null)
|
||||
continue;
|
||||
|
||||
if(!otherTile.Hotspot.Valid)
|
||||
HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume/4);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tile.Hotspot.State = (byte) (tile.Hotspot.Volume > Atmospherics.CellVolume * 0.4f ? 2 : 1);
|
||||
}
|
||||
|
||||
if (tile.Hotspot.Temperature > tile.MaxFireTemperatureSustained)
|
||||
tile.MaxFireTemperatureSustained = tile.Hotspot.Temperature;
|
||||
|
||||
if (_hotspotSoundCooldown++ == 0 && HotspotSound != null)
|
||||
{
|
||||
var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices);
|
||||
|
||||
// A few details on the audio parameters for fire.
|
||||
// The greater the fire state, the lesser the pitch variation.
|
||||
// The greater the fire state, the greater the volume.
|
||||
_audio.PlayPvs(HotspotSound, coordinates, HotspotSound.Params.WithVariation(0.15f / tile.Hotspot.State).WithVolume(-5f + 5f * tile.Hotspot.State));
|
||||
}
|
||||
|
||||
if (_hotspotSoundCooldown > HotspotSoundCooldownCycles)
|
||||
_hotspotSoundCooldown = 0;
|
||||
|
||||
// TODO ATMOS Maybe destroy location here?
|
||||
}
|
||||
|
||||
private void HotspotExpose(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile,
|
||||
float exposedTemperature, float exposedVolume, bool soh = false, EntityUid? sparkSourceUid = null)
|
||||
{
|
||||
if (tile.Air == null)
|
||||
return;
|
||||
|
||||
var oxygen = tile.Air.GetMoles(Gas.Oxygen);
|
||||
|
||||
if (oxygen < 0.5f)
|
||||
return;
|
||||
|
||||
var plasma = tile.Air.GetMoles(Gas.Plasma);
|
||||
var tritium = tile.Air.GetMoles(Gas.Tritium);
|
||||
|
||||
if (tile.Hotspot.Valid)
|
||||
{
|
||||
if (soh)
|
||||
{
|
||||
if (plasma > 0.5f || tritium > 0.5f)
|
||||
{
|
||||
if (tile.Hotspot.Temperature < exposedTemperature)
|
||||
tile.Hotspot.Temperature = exposedTemperature;
|
||||
if (tile.Hotspot.Volume < exposedVolume)
|
||||
tile.Hotspot.Volume = exposedVolume;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((exposedTemperature > Atmospherics.PlasmaMinimumBurnTemperature) && (plasma > 0.5f || tritium > 0.5f))
|
||||
{
|
||||
if (sparkSourceUid.HasValue)
|
||||
_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");
|
||||
|
||||
tile.Hotspot = new Hotspot
|
||||
{
|
||||
Volume = exposedVolume * 25f,
|
||||
Temperature = exposedTemperature,
|
||||
SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter,
|
||||
Valid = true,
|
||||
State = 1
|
||||
};
|
||||
|
||||
AddActiveTile(gridAtmosphere, tile);
|
||||
gridAtmosphere.HotspotTiles.Add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformHotspotExposure(TileAtmosphere tile)
|
||||
else
|
||||
{
|
||||
if (tile.Air == null || !tile.Hotspot.Valid) return;
|
||||
// Little baby fire. Set the sprite state based on the current size of the fire.
|
||||
tile.Hotspot.State = (byte)(tile.Hotspot.Volume > Atmospherics.CellVolume * 0.4f ? 2 : 1);
|
||||
}
|
||||
|
||||
tile.Hotspot.Bypassing = tile.Hotspot.SkippedFirstProcess && tile.Hotspot.Volume > tile.Air.Volume*0.95f;
|
||||
if (tile.Hotspot.Temperature > tile.MaxFireTemperatureSustained)
|
||||
tile.MaxFireTemperatureSustained = tile.Hotspot.Temperature;
|
||||
|
||||
if (tile.Hotspot.Bypassing)
|
||||
if (_hotspotSoundCooldown++ == 0 && HotspotSound != null)
|
||||
{
|
||||
var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices);
|
||||
|
||||
// A few details on the audio parameters for fire.
|
||||
// The greater the fire state, the lesser the pitch variation.
|
||||
// The greater the fire state, the greater the volume.
|
||||
_audio.PlayPvs(HotspotSound,
|
||||
coordinates,
|
||||
HotspotSound.Params.WithVariation(0.15f / tile.Hotspot.State)
|
||||
.WithVolume(-5f + 5f * tile.Hotspot.State));
|
||||
}
|
||||
|
||||
if (_hotspotSoundCooldown > HotspotSoundCooldownCycles)
|
||||
_hotspotSoundCooldown = 0;
|
||||
|
||||
// TODO ATMOS Maybe destroy location here?
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exposes a tile to a hotspot of given temperature and volume, igniting it if conditions are met.
|
||||
/// </summary>
|
||||
/// <param name="gridAtmosphere">The <see cref="GridAtmosphereComponent"/> of the grid the tile is on.</param>
|
||||
/// <param name="tile">The <see cref="TileAtmosphere"/> to expose.</param>
|
||||
/// <param name="exposedTemperature">The temperature of the hotspot to expose.
|
||||
/// You can think of this as exposing a temperature of a flame.</param>
|
||||
/// <param name="exposedVolume">The volume of the hotspot to expose.
|
||||
/// You can think of this as how big the flame is initially.
|
||||
/// Bigger flames will ramp a fire faster.</param>
|
||||
/// <param name="soh">Whether to "boost" a fire that's currently on the tile already.
|
||||
/// Does nothing if the tile isn't already a hotspot.
|
||||
/// This clamps the temperature and volume of the hotspot to the maximum
|
||||
/// of the provided parameters and whatever's on the tile.</param>
|
||||
/// <param name="sparkSourceUid">Entity that started the exposure for admin logging.</param>
|
||||
private void HotspotExpose(GridAtmosphereComponent gridAtmosphere,
|
||||
TileAtmosphere tile,
|
||||
float exposedTemperature,
|
||||
float exposedVolume,
|
||||
bool soh = false,
|
||||
EntityUid? sparkSourceUid = null)
|
||||
{
|
||||
if (tile.Air == null)
|
||||
return;
|
||||
|
||||
var oxygen = tile.Air.GetMoles(Gas.Oxygen);
|
||||
|
||||
if (oxygen < 0.5f)
|
||||
return;
|
||||
|
||||
var plasma = tile.Air.GetMoles(Gas.Plasma);
|
||||
var tritium = tile.Air.GetMoles(Gas.Tritium);
|
||||
|
||||
if (tile.Hotspot.Valid)
|
||||
{
|
||||
if (soh)
|
||||
{
|
||||
tile.Hotspot.Volume = tile.Air.ReactionResults[(byte)GasReaction.Fire] * Atmospherics.FireGrowthRate;
|
||||
tile.Hotspot.Temperature = tile.Air.Temperature;
|
||||
}
|
||||
else
|
||||
{
|
||||
var affected = tile.Air.RemoveVolume(tile.Hotspot.Volume);
|
||||
affected.Temperature = tile.Hotspot.Temperature;
|
||||
React(affected, tile);
|
||||
tile.Hotspot.Temperature = affected.Temperature;
|
||||
tile.Hotspot.Volume = affected.ReactionResults[(byte)GasReaction.Fire] * Atmospherics.FireGrowthRate;
|
||||
Merge(tile.Air, affected);
|
||||
if (plasma > 0.5f || tritium > 0.5f)
|
||||
{
|
||||
tile.Hotspot.Temperature = MathF.Max(tile.Hotspot.Temperature, exposedTemperature);
|
||||
tile.Hotspot.Volume = MathF.Max(tile.Hotspot.Volume, exposedVolume);
|
||||
}
|
||||
}
|
||||
|
||||
var fireEvent = new TileFireEvent(tile.Hotspot.Temperature, tile.Hotspot.Volume);
|
||||
_entSet.Clear();
|
||||
_lookup.GetLocalEntitiesIntersecting(tile.GridIndex, tile.GridIndices, _entSet, 0f);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var entity in _entSet)
|
||||
if (exposedTemperature > Atmospherics.PlasmaMinimumBurnTemperature && (plasma > 0.5f || tritium > 0.5f))
|
||||
{
|
||||
if (sparkSourceUid.HasValue)
|
||||
{
|
||||
RaiseLocalEvent(entity, ref fireEvent);
|
||||
_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");
|
||||
}
|
||||
|
||||
tile.Hotspot = new Hotspot
|
||||
{
|
||||
Volume = exposedVolume * 25f,
|
||||
Temperature = exposedTemperature,
|
||||
SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter,
|
||||
Valid = true,
|
||||
State = 1
|
||||
};
|
||||
|
||||
AddActiveTile(gridAtmosphere, tile);
|
||||
gridAtmosphere.HotspotTiles.Add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs hotspot exposure processing on a <see cref="TileAtmosphere"/>.
|
||||
/// </summary>
|
||||
/// <param name="tile">The <see cref="TileAtmosphere"/> to process.</param>
|
||||
private void PerformHotspotExposure(TileAtmosphere tile)
|
||||
{
|
||||
if (tile.Air == null || !tile.Hotspot.Valid)
|
||||
return;
|
||||
|
||||
// Determine if the tile has become a full-blown fire if the volume of the fire has effectively reached
|
||||
// the volume of the tile's air.
|
||||
tile.Hotspot.Bypassing = tile.Hotspot.SkippedFirstProcess && tile.Hotspot.Volume > tile.Air.Volume * 0.95f;
|
||||
|
||||
// If the tile is effectively a full fire, use the tile's air for reactions, don't bother partitioning.
|
||||
if (tile.Hotspot.Bypassing)
|
||||
{
|
||||
tile.Hotspot.Volume = tile.Air.ReactionResults[(byte)GasReaction.Fire] * Atmospherics.FireGrowthRate;
|
||||
tile.Hotspot.Temperature = tile.Air.Temperature;
|
||||
}
|
||||
// Otherwise, pull out a fraction of the tile's air (the current hotspot volume) to perform reactions on.
|
||||
else
|
||||
{
|
||||
var affected = tile.Air.RemoveVolume(tile.Hotspot.Volume);
|
||||
affected.Temperature = tile.Hotspot.Temperature;
|
||||
React(affected, tile);
|
||||
tile.Hotspot.Temperature = affected.Temperature;
|
||||
// Scale the fire based on the type of reaction that occured.
|
||||
tile.Hotspot.Volume = affected.ReactionResults[(byte)GasReaction.Fire] * Atmospherics.FireGrowthRate;
|
||||
Merge(tile.Air, affected);
|
||||
}
|
||||
|
||||
var fireEvent = new TileFireEvent(tile.Hotspot.Temperature, tile.Hotspot.Volume);
|
||||
_entSet.Clear();
|
||||
_lookup.GetLocalEntitiesIntersecting(tile.GridIndex, tile.GridIndices, _entSet, 0f);
|
||||
|
||||
foreach (var entity in _entSet)
|
||||
{
|
||||
RaiseLocalEvent(entity, ref fireEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,57 @@
|
||||
namespace Content.Server.Atmos
|
||||
namespace Content.Server.Atmos;
|
||||
|
||||
/// <summary>
|
||||
/// Internal Atmospherics struct that stores data about a hotspot in a tile.
|
||||
/// Hotspots are used to model (slow-spreading) fires and firestarters.
|
||||
/// </summary>
|
||||
public struct Hotspot
|
||||
{
|
||||
public struct Hotspot
|
||||
{
|
||||
[ViewVariables]
|
||||
public bool Valid;
|
||||
/// <summary>
|
||||
/// Whether this hotspot is currently representing fire and needs to be processed.
|
||||
/// Set when the hotspot "becomes alight". This is never set to false
|
||||
/// because Atmospherics will just assign <see cref="TileAtmosphere"/>
|
||||
/// a new <see cref="Hotspot"/> struct when the fire goes out.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Valid;
|
||||
|
||||
[ViewVariables]
|
||||
public bool SkippedFirstProcess;
|
||||
/// <summary>
|
||||
/// Whether this hotspot has skipped its first process cycle.
|
||||
/// AtmosphereSystem.Hotspot skips processing a hotspot beyond
|
||||
/// setting it to active (for LINDA processing) the first
|
||||
/// time it is processed.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool SkippedFirstProcess;
|
||||
|
||||
[ViewVariables]
|
||||
public bool Bypassing;
|
||||
/// <summary>
|
||||
/// <para>Whether this hotspot is currently using the tile for reacting and fire processing
|
||||
/// instead of a fraction of the tile's air.</para>
|
||||
///
|
||||
/// <para>When a tile is considered a hotspot, Hotspot will pull a fraction of that tile's
|
||||
/// air out of the tile and perform a reaction on that air, merging it back afterward.
|
||||
/// Bypassing triggers when the hotspot volume nears the tile's volume, making the system
|
||||
/// use the tile's GasMixture instead of pulling a fraction out.</para>
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Bypassing;
|
||||
|
||||
[ViewVariables]
|
||||
public float Temperature;
|
||||
/// <summary>
|
||||
/// Current temperature of the hotspot's volume, in Kelvin.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public float Temperature;
|
||||
|
||||
[ViewVariables]
|
||||
public float Volume;
|
||||
/// <summary>
|
||||
/// Current volume of the hotspot, in liters.
|
||||
/// You can think of this as the volume of the current fire in the tile.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public float Volume;
|
||||
|
||||
/// <summary>
|
||||
/// State for the fire sprite.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public byte State;
|
||||
}
|
||||
/// <summary>
|
||||
/// State for the fire sprite.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public byte State;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user