Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model static fires equalizing with the local atmosphere #32760

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions Content.Server/Atmos/Components/FlammableComponent.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,55 @@
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Prototypes;
using System.Linq;

namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public sealed partial class FlammableComponent : Component
{
// An array which represents the atmos gases as mols, Specifies 1 mol of Oxygen.
private static float[] _standardOxygenMols = new float[] { 1f }.Concat(Enumerable.Repeat(0f, Atmospherics.AdjustedNumberOfGases - 1)).ToArray();

[DataField]
public bool Resisting;

[ViewVariables(VVAccess.ReadWrite)]
/// <summary>
/// A gas mix which specifies the minimum mols of each gas needed for the entity to burn. Set to null to burn without atmosphere.
/// </summary>
[DataField]
public GasMixture? FuelGasMix = new GasMixture(_standardOxygenMols, Atmospherics.T20C, 1f);

[DataField]
public bool OnFire;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float FireStacks;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MaximumFireStacks = 10f;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MinimumFireStacks = -10f;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public string FlammableFixtureID = "flammable";

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MinIgnitionTemperature = 373.15f;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float PeakFlameTemperature = 1500.00f; // vaguely how hot an incenerator gets.

[DataField]
public bool FireSpread { get; private set; } = false;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public bool CanResistFire { get; private set; } = false;

[DataField(required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier Damage = new(); // Empty by default, we don't want any funny NREs.

/// <summary>
Expand All @@ -56,31 +61,34 @@ public sealed partial class FlammableComponent : Component
/// <summary>
/// Should the component be set on fire by interactions with isHot entities
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public bool AlwaysCombustible = false;

/// <summary>
/// Can the component anyhow lose its FireStacks?
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public bool CanExtinguish = true;

/// <summary>
/// How many firestacks should be applied to component when being set on fire?
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float FirestacksOnIgnite = 2.0f;

/// <summary>
/// Determines how quickly the object will fade out. With positive values, the object will flare up instead of going out.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float FirestackFade = -0.1f;

[DataField]
public ProtoId<AlertPrototype> FireAlert = "Fire";

/// <summary>
/// A maximum quantity of gas to be added to the atmosphere every update while on fire.
/// </summary>
[DataField]
public GasMixture? EmissiveGasMix;
}
}
51 changes: 44 additions & 7 deletions Content.Server/Atmos/EntitySystems/FlammableSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Content.Shared.Atmos.Piping.Binary.Components;

namespace Content.Server.Atmos.EntitySystems
{
Expand Down Expand Up @@ -82,6 +83,7 @@ public override void Initialize()
SubscribeLocalEvent<ExtinguishOnInteractComponent, ActivateInWorldEvent>(OnExtinguishActivateInWorld);

SubscribeLocalEvent<IgniteOnHeatDamageComponent, DamageChangedEvent>(OnDamageChanged);

IProduceWidgets marked this conversation as resolved.
Show resolved Hide resolved
}

private void OnMeleeHit(EntityUid uid, IgniteOnMeleeHitComponent component, MeleeHitEvent args)
Expand Down Expand Up @@ -413,7 +415,6 @@ public override void Update(float frameTime)

_timer -= UpdateTime;

// TODO: This needs cleanup to take off the crust from TemperatureComponent and shit.
var query = EntityQueryEnumerator<FlammableComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var flammable, out _))
{
Expand All @@ -433,20 +434,56 @@ public override void Update(float frameTime)

if (flammable.FireStacks > 0)
{
var air = _atmosphereSystem.GetContainingMixture(uid);
var air = _atmosphereSystem.GetContainingMixture(uid, false, true);
IProduceWidgets marked this conversation as resolved.
Show resolved Hide resolved

// If we're in an oxygenless environment, put the fire out.
if (air == null || air.GetMoles(Gas.Oxygen) < 1f)
if (flammable.FuelGasMix != null)
{
Extinguish(uid, flammable);
continue;
// If we're in no atmos extinguish.
if (air == null)
{
Extinguish(uid, flammable);
continue;
}

// If our local atmos doesnt have enough of the required gases extinguish.
for (int i = 0; i < Atmospherics.AdjustedNumberOfGases; i++)
{
if (flammable.FuelGasMix.GetMoles(i) > air.GetMoles(i))
{
Extinguish(uid, flammable);
continue;
IProduceWidgets marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

var source = EnsureComp<IgnitionSourceComponent>(uid);
_ignitionSourceSystem.SetIgnited((uid, source));

if (TryComp(uid, out TemperatureComponent? temp))
_temperatureSystem.ChangeHeat(uid, 12500 * flammable.FireStacks, false, temp);
{
// get hot
if (_atmosphereSystem.Superconduction) // superconductivity ***should*** mean an equilibrium temperature gets reached with the environment.
{
_temperatureSystem.ChangeHeat(uid, 12500 * flammable.FireStacks, false, temp);
}
else // without superconductivity we need to prevent thermal runaway. Not guarunteed to be equivalent for balancing purposes.
{
var maxDeltaT = flammable.PeakFlameTemperature - temp.CurrentTemperature;
if (maxDeltaT > 0) // we dont want to burn and get colder.
{
var tempBump = MathF.Sqrt(maxDeltaT) * flammable.FireStacks * 25; //monotonic function, slows as it reaches maxT
_temperatureSystem.ChangeHeat(uid, tempBump, false, temp);
}
}

// release gas
if (air != null && flammable.EmissiveGasMix != null)
{
flammable.EmissiveGasMix.Temperature = temp.CurrentTemperature;
var releasingGas = flammable.EmissiveGasMix.Clone(); // generate gas for the entity's entire burning lifespan, but we use ReleaseGasTo to handle temperature/pressure for us since those will change for other reasons.
_atmosphereSystem.ReleaseGasTo(releasingGas, air, releasingGas.Pressure); // doing it this way means that we dont need to track the entity damage values or know its destructible or mobstate thresholds.
} // the downside, and a possible later rework, is that you ""lose"" some gas if the candle is burning in an atmosphere where it can't emit due to pressure.
IProduceWidgets marked this conversation as resolved.
Show resolved Hide resolved
} // the yml is also slightly cumbersome, because we now specify a "maximum release mix per update (second)" instead of a total gasmix in the entity.

var ev = new GetFireProtectionEvent();
// let the thing on fire handle it
Expand Down
10 changes: 10 additions & 0 deletions Resources/Prototypes/Catalog/Cargo/cargo_atmospherics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,13 @@
# cost: 15500
# category: cargoproduct-category-name-atmospherics
# group: market

- type: cargoProduct
id: AtmosphericsCandles
icon:
sprite: Objects/Misc/candles.rsi
state: candle-big
product: CrateCandlesAir
cost: 2500 # its ~ 32000 mols of Air mix potential. Cheap though because no cannister, and youve got to cool it and collect it to use it.
category: cargoproduct-category-name-atmospherics
group: market
11 changes: 11 additions & 0 deletions Resources/Prototypes/Catalog/Fills/Boxes/engineering.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- type: entity
name: air candle box
parent: BoxCandle
id: BoxCandleAir
components:
- type: StorageFill
contents:
- id: CandleGasNitrogen
amount: 9
- id: CandleGasOxygen
amount: 3
12 changes: 12 additions & 0 deletions Resources/Prototypes/Catalog/Fills/Crates/engineering.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,15 @@
- type: StorageFill
contents:
- id: SpaceHeaterFlatpack

- type: entity
id: CrateCandlesAir
parent: CrateEngineeringSecure
name: air candle crate
description: A crate containing 2 boxes of air gas candles.
components:
- type: StorageFill
contents:
- id: BoxCandleAir
amount: 2
- id: BoxFlare
2 changes: 1 addition & 1 deletion Resources/Prototypes/Entities/Objects/Misc/candles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
canResistFire: false
alwaysCombustible: true
canExtinguish: true
firestacksOnIgnite: 3.0
firestacksOnIgnite: 3.3
IProduceWidgets marked this conversation as resolved.
Show resolved Hide resolved
firestackFade: -0.01
damage:
types:
Expand Down
Loading
Loading