Fire damage (#2024)
* Moved the uplink creation code to the PresetSuspicion.Start method to ensure uplink created when we give the traitor role Moved the starting TC balance to cvars * Added component to handle interaction with Atmospheric system Added damage from high and cold temperature * renamed AtmoExposable to AtmosExposed moved AtmosExposed updates to its own system refactored TemperatureComponent renamed fire to heat added null check for Air added self-heating and self-cooling to body system * small refactoring for checking on airless tile in MetabolismComponent * Added component to handle interaction with Atmospheric system Added damage from high and cold temperature * renamed AtmoExposable to AtmosExposed moved AtmosExposed updates to its own system refactored TemperatureComponent renamed fire to heat added null check for Air added self-heating and self-cooling to body system * small refactoring for checking on airless tile in MetabolismComponent * Removed Pressure property from BarotraumaComponent Changed CanShiver method to match style of other CanX method in ActionBlockerSystem * Merged EntityCoordinates and changed components to reflect the change * Fix typo * Wrapped string to Loc.GetString Added CanSweat Refactored dead state check
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
"CloningPod",
|
"CloningPod",
|
||||||
"Destructible",
|
"Destructible",
|
||||||
"Temperature",
|
"Temperature",
|
||||||
|
"AtmosExposed",
|
||||||
"Explosive",
|
"Explosive",
|
||||||
"OnUseTimerTrigger",
|
"OnUseTimerTrigger",
|
||||||
"ToolboxElectricalFill",
|
"ToolboxElectricalFill",
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ namespace Content.Server.Atmos
|
|||||||
return gridAtmos?.GetTile(coordinates);
|
return gridAtmos?.GetTile(coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GasMixture? GetTileAir(this EntityCoordinates coordinates)
|
public static GasMixture? GetTileAir(this EntityCoordinates coordinates, IEntityManager? entityManager = null)
|
||||||
{
|
{
|
||||||
return coordinates.GetTileAtmosphere()?.Air;
|
return coordinates.GetTileAtmosphere(entityManager)?.Air;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetTileAtmosphere(this EntityCoordinates coordinates, [MaybeNullWhen(false)] out TileAtmosphere atmosphere)
|
public static bool TryGetTileAtmosphere(this EntityCoordinates coordinates, [MaybeNullWhen(false)] out TileAtmosphere atmosphere)
|
||||||
@@ -30,10 +30,10 @@ namespace Content.Server.Atmos
|
|||||||
return !Equals(atmosphere = coordinates.GetTileAtmosphere()!, default);
|
return !Equals(atmosphere = coordinates.GetTileAtmosphere()!, default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetTileAir(this EntityCoordinates coordinates, [MaybeNullWhen(false)] out GasMixture air)
|
public static bool TryGetTileAir(this EntityCoordinates coordinates, [MaybeNullWhen(false)] out GasMixture air, IEntityManager? entityManager = null)
|
||||||
{
|
{
|
||||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||||
return !Equals(air = coordinates.GetTileAir()!, default);
|
return !Equals(air = coordinates.GetTileAir(entityManager)!, default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TileAtmosphere? GetTileAtmosphere(this MapIndices indices, GridId gridId)
|
public static TileAtmosphere? GetTileAtmosphere(this MapIndices indices, GridId gridId)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Content.Server.Atmos
|
|||||||
public int AtmosCooldown { get; set; } = 0;
|
public int AtmosCooldown { get; set; } = 0;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private float _temperature = Atmospherics.T20C;
|
public float Temperature {get; private set; } = Atmospherics.T20C;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private float _temperatureArchived = Atmospherics.T20C;
|
private float _temperatureArchived = Atmospherics.T20C;
|
||||||
@@ -132,7 +132,7 @@ namespace Content.Server.Atmos
|
|||||||
{
|
{
|
||||||
Air?.Archive();
|
Air?.Archive();
|
||||||
_archivedCycle = fireCount;
|
_archivedCycle = fireCount;
|
||||||
_temperatureArchived = _temperature;
|
_temperatureArchived = Temperature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HotspotExpose(float exposedTemperature, float exposedVolume, bool soh = false)
|
public void HotspotExpose(float exposedTemperature, float exposedVolume, bool soh = false)
|
||||||
@@ -869,10 +869,10 @@ namespace Content.Server.Atmos
|
|||||||
// Conduct with air on my tile if I have it
|
// Conduct with air on my tile if I have it
|
||||||
if (!BlocksAir)
|
if (!BlocksAir)
|
||||||
{
|
{
|
||||||
_temperature = Air.TemperatureShare(ThermalConductivity, _temperature, HeatCapacity);
|
Temperature = Air.TemperatureShare(ThermalConductivity, Temperature, HeatCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishSuperconduction(BlocksAir ? _temperature : Air.Temperature);
|
FinishSuperconduction(BlocksAir ? Temperature : Air.Temperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FinishSuperconduction(float temperature)
|
private void FinishSuperconduction(float temperature)
|
||||||
@@ -897,7 +897,7 @@ namespace Content.Server.Atmos
|
|||||||
other.TemperatureShareMutualSolid(this, ThermalConductivity);
|
other.TemperatureShareMutualSolid(this, ThermalConductivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
TemperatureExpose(null, _temperature, _gridAtmosphereComponent.GetVolumeForCells(1));
|
TemperatureExpose(null, Temperature, _gridAtmosphereComponent.GetVolumeForCells(1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -915,8 +915,8 @@ namespace Content.Server.Atmos
|
|||||||
|
|
||||||
private void TemperatureShareOpenToSolid(TileAtmosphere other)
|
private void TemperatureShareOpenToSolid(TileAtmosphere other)
|
||||||
{
|
{
|
||||||
other._temperature =
|
other.Temperature =
|
||||||
Air.TemperatureShare(other.ThermalConductivity, other._temperature, other.HeatCapacity);
|
Air.TemperatureShare(other.ThermalConductivity, other.Temperature, other.HeatCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TemperatureShareMutualSolid(TileAtmosphere other, float conductionCoefficient)
|
private void TemperatureShareMutualSolid(TileAtmosphere other, float conductionCoefficient)
|
||||||
@@ -928,15 +928,15 @@ namespace Content.Server.Atmos
|
|||||||
var heat = conductionCoefficient * deltaTemperature *
|
var heat = conductionCoefficient * deltaTemperature *
|
||||||
(HeatCapacity * other.HeatCapacity / (HeatCapacity + other.HeatCapacity));
|
(HeatCapacity * other.HeatCapacity / (HeatCapacity + other.HeatCapacity));
|
||||||
|
|
||||||
_temperature -= heat / HeatCapacity;
|
Temperature -= heat / HeatCapacity;
|
||||||
other._temperature += heat / other.HeatCapacity;
|
other.Temperature += heat / other.HeatCapacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RadiateToSpace()
|
public void RadiateToSpace()
|
||||||
{
|
{
|
||||||
// Considering 0ºC as the break even point for radiation in and out.
|
// Considering 0ºC as the break even point for radiation in and out.
|
||||||
if (_temperature > Atmospherics.T0C)
|
if (Temperature > Atmospherics.T0C)
|
||||||
{
|
{
|
||||||
// Hardcoded space temperature.
|
// Hardcoded space temperature.
|
||||||
var deltaTemperature = (_temperatureArchived - Atmospherics.TCMB);
|
var deltaTemperature = (_temperatureArchived - Atmospherics.TCMB);
|
||||||
@@ -945,7 +945,7 @@ namespace Content.Server.Atmos
|
|||||||
var heat = ThermalConductivity * deltaTemperature * (HeatCapacity *
|
var heat = ThermalConductivity * deltaTemperature * (HeatCapacity *
|
||||||
Atmospherics.HeatCapacityVacuum / (HeatCapacity + Atmospherics.HeatCapacityVacuum));
|
Atmospherics.HeatCapacityVacuum / (HeatCapacity + Atmospherics.HeatCapacityVacuum));
|
||||||
|
|
||||||
_temperature -= heat;
|
Temperature -= heat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Content.Server.Atmos;
|
||||||
|
using Content.Server.GameObjects.Components.Temperature;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Atmos
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents that entity can be exposed to Atmo
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class AtmosExposedComponent
|
||||||
|
: Component
|
||||||
|
{
|
||||||
|
public override string Name => "AtmosExposed";
|
||||||
|
|
||||||
|
public void Update(TileAtmosphere tile, float timeDelta)
|
||||||
|
{
|
||||||
|
if (Owner.TryGetComponent<TemperatureComponent>(out var temperatureComponent))
|
||||||
|
{
|
||||||
|
if (tile.Air != null)
|
||||||
|
{
|
||||||
|
var temperatureDelta = tile.Air.Temperature - temperatureComponent.CurrentTemperature;
|
||||||
|
var heat = temperatureDelta * (tile.Air.HeatCapacity * temperatureComponent.HeatCapacity / (tile.Air.HeatCapacity + temperatureComponent.HeatCapacity));
|
||||||
|
temperatureComponent.ReceiveHeat(heat);
|
||||||
|
}
|
||||||
|
temperatureComponent.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Owner.TryGetComponent<BarotraumaComponent>(out var barotraumaComponent))
|
||||||
|
{
|
||||||
|
barotraumaComponent.Update(tile.Air?.Pressure ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Server.Interfaces.GameObjects;
|
using Content.Server.Interfaces.GameObjects;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Mobs;
|
using Content.Shared.GameObjects.Components.Mobs;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Atmos
|
namespace Content.Server.GameObjects.Components.Atmos
|
||||||
@@ -19,21 +17,14 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class BarotraumaComponent : Component
|
public class BarotraumaComponent : Component
|
||||||
{
|
{
|
||||||
[Robust.Shared.IoC.Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
|
|
||||||
public override string Name => "Barotrauma";
|
public override string Name => "Barotrauma";
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Update(float frameTime)
|
public void Update(float airPressure)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IDamageableComponent damageable)) return;
|
if (!Owner.TryGetComponent(out IDamageableComponent damageable)) return;
|
||||||
Owner.TryGetComponent(out ServerStatusEffectsComponent status);
|
Owner.TryGetComponent(out ServerStatusEffectsComponent status);
|
||||||
|
|
||||||
var coordinates = Owner.Transform.Coordinates;
|
|
||||||
var gridAtmos = EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(coordinates.GetGridId(_entityManager));
|
|
||||||
var tile = gridAtmos?.GetTile(coordinates);
|
|
||||||
|
|
||||||
var pressure = 1f;
|
|
||||||
var highPressureMultiplier = 1f;
|
var highPressureMultiplier = 1f;
|
||||||
var lowPressureMultiplier = 1f;
|
var lowPressureMultiplier = 1f;
|
||||||
|
|
||||||
@@ -43,8 +34,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
lowPressureMultiplier *= protection.LowPressureMultiplier;
|
lowPressureMultiplier *= protection.LowPressureMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile?.Air != null)
|
var pressure = MathF.Max(airPressure, 1f);
|
||||||
pressure = MathF.Max(tile.Air.Pressure, 1f);
|
|
||||||
|
|
||||||
switch (pressure)
|
switch (pressure)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,15 +2,20 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Atmos;
|
using Content.Server.Atmos;
|
||||||
using Content.Server.GameObjects.Components.Atmos;
|
|
||||||
using Content.Server.GameObjects.Components.Body.Circulatory;
|
using Content.Server.GameObjects.Components.Body.Circulatory;
|
||||||
|
using Content.Server.GameObjects.Components.Temperature;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
|
using Content.Shared.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.Interfaces;
|
||||||
using Content.Shared.Interfaces.Chemistry;
|
using Content.Shared.Interfaces.Chemistry;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -21,11 +26,16 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
public class MetabolismComponent : Component
|
public class MetabolismComponent : Component
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
|
||||||
public override string Name => "Metabolism";
|
public override string Name => "Metabolism";
|
||||||
|
|
||||||
private float _accumulatedFrameTime;
|
private float _accumulatedFrameTime;
|
||||||
|
|
||||||
|
private bool _isShivering;
|
||||||
|
private bool _isSweating;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] private int _suffocationDamage;
|
[ViewVariables(VVAccess.ReadWrite)] private int _suffocationDamage;
|
||||||
|
|
||||||
[ViewVariables] public Dictionary<Gas, float> NeedsGases { get; set; }
|
[ViewVariables] public Dictionary<Gas, float> NeedsGases { get; set; }
|
||||||
@@ -34,6 +44,47 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
|
|
||||||
[ViewVariables] public Dictionary<Gas, float> DeficitGases { get; set; }
|
[ViewVariables] public Dictionary<Gas, float> DeficitGases { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Heat generated due to metabolism. It's generated via metabolism
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public float MetabolismHeat { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Heat output via radiation.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public float RadiatedHeat { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum heat regulated via sweat
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public float SweatHeatRegulation { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum heat regulated via shivering
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public float ShiveringHeatRegulation { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of heat regulation that represents thermal regulation processes not
|
||||||
|
/// explicitly coded.
|
||||||
|
/// </summary>
|
||||||
|
public float ImplicitHeatRegulation { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normal body temperature
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public float NormalBodyTemperature { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deviation from normal temperature for body to start thermal regulation
|
||||||
|
/// </summary>
|
||||||
|
public float ThermalRegulationTemperatureThreshold { get; private set; }
|
||||||
|
|
||||||
[ViewVariables] public bool Suffocating => SuffocatingPercentage() > 0;
|
[ViewVariables] public bool Suffocating => SuffocatingPercentage() > 0;
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
@@ -43,6 +94,14 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
serializer.DataField(this, b => b.NeedsGases, "needsGases", new Dictionary<Gas, float>());
|
serializer.DataField(this, b => b.NeedsGases, "needsGases", new Dictionary<Gas, float>());
|
||||||
serializer.DataField(this, b => b.ProducesGases, "producesGases", new Dictionary<Gas, float>());
|
serializer.DataField(this, b => b.ProducesGases, "producesGases", new Dictionary<Gas, float>());
|
||||||
serializer.DataField(this, b => b.DeficitGases, "deficitGases", new Dictionary<Gas, float>());
|
serializer.DataField(this, b => b.DeficitGases, "deficitGases", new Dictionary<Gas, float>());
|
||||||
|
serializer.DataField(this, b => b.MetabolismHeat, "metabolismHeat", 0);
|
||||||
|
serializer.DataField(this, b => b.RadiatedHeat, "radiatedHeat", 0);
|
||||||
|
serializer.DataField(this, b => b.SweatHeatRegulation, "sweatHeatRegulation", 0);
|
||||||
|
serializer.DataField(this, b => b.ShiveringHeatRegulation, "shiveringHeatRegulation", 0);
|
||||||
|
serializer.DataField(this, b => b.ImplicitHeatRegulation, "implicitHeatRegulation", 0);
|
||||||
|
serializer.DataField(this, b => b.NormalBodyTemperature, "normalBodyTemperature", 0);
|
||||||
|
serializer.DataField(this, b => b.ThermalRegulationTemperatureThreshold,
|
||||||
|
"thermalRegulationTemperatureThreshold", 0);
|
||||||
serializer.DataField(ref _suffocationDamage, "suffocationDamage", 1);
|
serializer.DataField(ref _suffocationDamage, "suffocationDamage", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +211,76 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
ClampDeficit();
|
ClampDeficit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process thermal regulation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frameTime"></param>
|
||||||
|
private void ProcessThermalRegulation(float frameTime)
|
||||||
|
{
|
||||||
|
if (!Owner.TryGetComponent(out TemperatureComponent temperatureComponent)) return;
|
||||||
|
temperatureComponent.ReceiveHeat(MetabolismHeat);
|
||||||
|
temperatureComponent.RemoveHeat(RadiatedHeat);
|
||||||
|
|
||||||
|
// implicit heat regulation
|
||||||
|
var tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - NormalBodyTemperature);
|
||||||
|
var targetHeat = tempDiff * temperatureComponent.HeatCapacity;
|
||||||
|
if (temperatureComponent.CurrentTemperature > NormalBodyTemperature)
|
||||||
|
{
|
||||||
|
temperatureComponent.RemoveHeat(Math.Min(targetHeat, ImplicitHeatRegulation));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temperatureComponent.ReceiveHeat(Math.Min(targetHeat, ImplicitHeatRegulation));
|
||||||
|
}
|
||||||
|
|
||||||
|
// recalc difference and target heat
|
||||||
|
tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - NormalBodyTemperature);
|
||||||
|
targetHeat = tempDiff * temperatureComponent.HeatCapacity;
|
||||||
|
|
||||||
|
// if body temperature is not within comfortable, thermal regulation
|
||||||
|
// processes starts
|
||||||
|
if (tempDiff < ThermalRegulationTemperatureThreshold)
|
||||||
|
{
|
||||||
|
if (_isShivering || _isSweating)
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(Loc.GetString("You feel comfortable"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_isShivering = false;
|
||||||
|
_isSweating = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (temperatureComponent.CurrentTemperature > NormalBodyTemperature)
|
||||||
|
{
|
||||||
|
if (!ActionBlockerSystem.CanSweat(Owner)) return;
|
||||||
|
if (!_isSweating)
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(Loc.GetString("You are sweating"));
|
||||||
|
_isSweating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// creadth: sweating does not help in airless environment
|
||||||
|
if (Owner.Transform.Coordinates.TryGetTileAir(out _, _entityManager))
|
||||||
|
{
|
||||||
|
temperatureComponent.RemoveHeat(Math.Min(targetHeat, SweatHeatRegulation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!ActionBlockerSystem.CanShiver(Owner)) return;
|
||||||
|
if (!_isShivering)
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(Loc.GetString("You are shivering"));
|
||||||
|
_isShivering = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
temperatureComponent.ReceiveHeat(Math.Min(targetHeat, ShiveringHeatRegulation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loops through each reagent in _internalSolution,
|
/// Loops through each reagent in _internalSolution,
|
||||||
/// and calls <see cref="IMetabolizable.Metabolize"/> for each of them.
|
/// and calls <see cref="IMetabolizable.Metabolize"/> for each of them.
|
||||||
@@ -196,6 +325,12 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
/// </param>
|
/// </param>
|
||||||
public void Update(float frameTime)
|
public void Update(float frameTime)
|
||||||
{
|
{
|
||||||
|
if (!Owner.TryGetComponent<IDamageableComponent>(out var damageable) ||
|
||||||
|
damageable.CurrentDamageState == DamageState.Dead)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_accumulatedFrameTime += frameTime;
|
_accumulatedFrameTime += frameTime;
|
||||||
|
|
||||||
if (_accumulatedFrameTime < 1)
|
if (_accumulatedFrameTime < 1)
|
||||||
@@ -207,9 +342,9 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
|
|
||||||
ProcessGases(frameTime);
|
ProcessGases(frameTime);
|
||||||
ProcessNutrients(frameTime);
|
ProcessNutrients(frameTime);
|
||||||
|
ProcessThermalRegulation(frameTime);
|
||||||
|
|
||||||
if (Suffocating &&
|
if (Suffocating)
|
||||||
Owner.TryGetComponent(out IDamageableComponent damageable))
|
|
||||||
{
|
{
|
||||||
// damageable.ChangeDamage(DamageClass.Airloss, _suffocationDamage, false);
|
// damageable.ChangeDamage(DamageClass.Airloss, _suffocationDamage, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,103 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
using Content.Shared.Maths;
|
using Content.Shared.Maths;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Components;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Temperature
|
namespace Content.Server.GameObjects.Components.Temperature
|
||||||
{
|
{
|
||||||
public interface ITemperatureComponent : IComponent
|
|
||||||
{
|
|
||||||
float CurrentTemperature { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles changing temperature,
|
/// Handles changing temperature,
|
||||||
/// informing others of the current temperature,
|
/// informing others of the current temperature,
|
||||||
/// and taking fire damage from high temperature.
|
/// and taking fire damage from high temperature.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class TemperatureComponent : Component, ITemperatureComponent
|
public class TemperatureComponent : Component
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string Name => "Temperature";
|
public override string Name => "Temperature";
|
||||||
|
|
||||||
//TODO: should be programmatic instead of how it currently is
|
[ViewVariables] public float CurrentTemperature { get => _currentTemperature; set => _currentTemperature = value; }
|
||||||
[ViewVariables] public float CurrentTemperature { get; private set; } = PhysicalConstants.ZERO_CELCIUS;
|
|
||||||
|
|
||||||
float _fireDamageThreshold = 0;
|
[ViewVariables] public float HeatDamageThreshold => _heatDamageThreshold;
|
||||||
float _fireDamageCoefficient = 1;
|
[ViewVariables] public float ColdDamageThreshold => _coldDamageThreshold;
|
||||||
|
[ViewVariables] public float TempDamageCoefficient => _tempDamageCoefficient;
|
||||||
|
[ViewVariables] public float HeatCapacity {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Owner.TryGetComponent<ICollidableComponent>(out var physics))
|
||||||
|
{
|
||||||
|
return SpecificHeat * physics.Mass;
|
||||||
|
}
|
||||||
|
|
||||||
float _secondsSinceLastDamageUpdate = 0;
|
return Atmospherics.MinimumHeatCapacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ViewVariables] public float SpecificHeat => _specificHeat;
|
||||||
|
|
||||||
|
private float _heatDamageThreshold;
|
||||||
|
private float _coldDamageThreshold;
|
||||||
|
private float _tempDamageCoefficient;
|
||||||
|
private float _currentTemperature;
|
||||||
|
private float _specificHeat;
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
{
|
{
|
||||||
base.ExposeData(serializer);
|
base.ExposeData(serializer);
|
||||||
|
|
||||||
serializer.DataField(ref _fireDamageThreshold, "firedamagethreshold", 0);
|
serializer.DataField(ref _heatDamageThreshold, "heatDamageThreshold", 0);
|
||||||
serializer.DataField(ref _fireDamageCoefficient, "firedamagecoefficient", 1);
|
serializer.DataField(ref _coldDamageThreshold, "coldDamageThreshold", 0);
|
||||||
|
serializer.DataField(ref _tempDamageCoefficient, "tempDamageCoefficient", 1);
|
||||||
|
serializer.DataField(ref _currentTemperature, "currentTemperature", Atmospherics.T20C);
|
||||||
|
serializer.DataField(ref _specificHeat, "specificHeat", Atmospherics.MinimumHeatCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
public void Update()
|
||||||
public void OnUpdate(float frameTime)
|
|
||||||
{
|
{
|
||||||
var fireDamage =
|
var tempDamage = 0;
|
||||||
(int) Math.Floor(Math.Max(0, CurrentTemperature - _fireDamageThreshold) / _fireDamageCoefficient);
|
DamageType? damageType = null;
|
||||||
|
if (CurrentTemperature >= _heatDamageThreshold)
|
||||||
_secondsSinceLastDamageUpdate += frameTime;
|
|
||||||
|
|
||||||
Owner.TryGetComponent(out IDamageableComponent component);
|
|
||||||
|
|
||||||
while (_secondsSinceLastDamageUpdate >= 1)
|
|
||||||
{
|
{
|
||||||
component?.ChangeDamage(DamageType.Heat, fireDamage, false, null);
|
tempDamage = (int) Math.Floor((CurrentTemperature - _heatDamageThreshold) * _tempDamageCoefficient);
|
||||||
_secondsSinceLastDamageUpdate -= 1;
|
damageType = DamageType.Heat;
|
||||||
}
|
}
|
||||||
|
else if (CurrentTemperature <= _coldDamageThreshold)
|
||||||
|
{
|
||||||
|
tempDamage = (int) Math.Floor((_coldDamageThreshold - CurrentTemperature) * _tempDamageCoefficient);
|
||||||
|
damageType = DamageType.Cold;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!damageType.HasValue) return;
|
||||||
|
|
||||||
|
if (!Owner.TryGetComponent(out IDamageableComponent component)) return;
|
||||||
|
component.ChangeDamage(damageType.Value, tempDamage, false);
|
||||||
|
Debug.Write($"Temp is: {CurrentTemperature}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forcefully give heat to this component
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="heatAmount"></param>
|
||||||
|
public void ReceiveHeat(float heatAmount)
|
||||||
|
{
|
||||||
|
CurrentTemperature += heatAmount / HeatCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forcefully remove heat from this component
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="heatAmount"></param>
|
||||||
|
public void RemoveHeat(float heatAmount)
|
||||||
|
{
|
||||||
|
CurrentTemperature -= heatAmount / HeatCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using Content.Server.Atmos;
|
||||||
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class AtmosExposedSystem
|
||||||
|
: EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
private const float UpdateDelay = 3f;
|
||||||
|
private float _lastUpdate;
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
_lastUpdate += frameTime;
|
||||||
|
if (_lastUpdate < UpdateDelay) return;
|
||||||
|
var atmoSystem = EntitySystemManager.GetEntitySystem<AtmosphereSystem>();
|
||||||
|
// creadth: everything exposable by atmo should be updated as well
|
||||||
|
foreach (var atmosExposedComponent in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>())
|
||||||
|
{
|
||||||
|
var tile = atmosExposedComponent.Owner.Transform.Coordinates.GetTileAtmosphere(_entityManager);
|
||||||
|
if (tile == null) continue;
|
||||||
|
atmosExposedComponent.Update(tile, _lastUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastUpdate = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Atmos;
|
using Content.Server.Atmos;
|
||||||
using Content.Server.Atmos.Reactions;
|
using Content.Server.Atmos.Reactions;
|
||||||
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
using Content.Shared.GameObjects.EntitySystems.Atmos;
|
using Content.Shared.GameObjects.EntitySystems.Atmos;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -64,8 +65,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
|
|
||||||
foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery<IMapGridComponent, IGridAtmosphereComponent>())
|
foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery<IMapGridComponent, IGridAtmosphereComponent>())
|
||||||
{
|
{
|
||||||
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex))
|
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
gridAtmosphereComponent.Update(frameTime);
|
gridAtmosphereComponent.Update(frameTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
using Content.Server.GameObjects.Components.Atmos;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.EntitySystems
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
public class BarotraumaSystem : EntitySystem
|
|
||||||
{
|
|
||||||
private const float TimePerUpdate = 3f;
|
|
||||||
|
|
||||||
private float _timer = 0f;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
_timer += frameTime;
|
|
||||||
|
|
||||||
if (_timer < TimePerUpdate) return;
|
|
||||||
|
|
||||||
_timer = 0f;
|
|
||||||
|
|
||||||
foreach (var barotraumaComp in ComponentManager.EntityQuery<BarotraumaComponent>())
|
|
||||||
{
|
|
||||||
barotraumaComp.Update(frameTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Content.Server.GameObjects.Components.Temperature;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.EntitySystems
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
internal sealed class TemperatureSystem : EntitySystem
|
|
||||||
{
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
foreach (var comp in ComponentManager.EntityQuery<TemperatureComponent>())
|
|
||||||
{
|
|
||||||
comp.OnUpdate(frameTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -260,6 +260,10 @@ namespace Content.Shared.GameObjects.Components.Mobs
|
|||||||
|
|
||||||
public bool CanUnequip() => (!Stunned);
|
public bool CanUnequip() => (!Stunned);
|
||||||
public bool CanChangeDirection() => true;
|
public bool CanChangeDirection() => true;
|
||||||
|
|
||||||
|
public bool CanShiver() => !Stunned;
|
||||||
|
public bool CanSweat() => true;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
|
|||||||
@@ -69,5 +69,8 @@ namespace Content.Shared.GameObjects.Components.Mobs.State
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanShiver() => false;
|
||||||
|
public bool CanSweat() => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ namespace Content.Shared.GameObjects.Components.Observer
|
|||||||
public bool CanPickup() => false;
|
public bool CanPickup() => false;
|
||||||
public bool CanEmote() => false;
|
public bool CanEmote() => false;
|
||||||
public bool CanAttack() => false;
|
public bool CanAttack() => false;
|
||||||
|
public bool CanShiver() => false;
|
||||||
|
public bool CanSweat() => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Robust.Shared.GameObjects.Systems;
|
using System.Linq;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
|
||||||
namespace Content.Shared.GameObjects.EntitySystems
|
namespace Content.Shared.GameObjects.EntitySystems
|
||||||
@@ -24,6 +25,9 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
bool CanUnequip() => true;
|
bool CanUnequip() => true;
|
||||||
|
|
||||||
bool CanChangeDirection() => true;
|
bool CanChangeDirection() => true;
|
||||||
|
|
||||||
|
bool CanShiver() => true;
|
||||||
|
bool CanSweat() => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -35,10 +39,11 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
public static bool CanMove(IEntity entity)
|
public static bool CanMove(IEntity entity)
|
||||||
{
|
{
|
||||||
bool canmove = true;
|
bool canmove = true;
|
||||||
foreach(var actionblockercomponents in entity.GetAllComponents<IActionBlocker>())
|
foreach (var actionblockercomponents in entity.GetAllComponents<IActionBlocker>())
|
||||||
{
|
{
|
||||||
canmove &= actionblockercomponents.CanMove(); // Sets var to false if false
|
canmove &= actionblockercomponents.CanMove(); // Sets var to false if false
|
||||||
}
|
}
|
||||||
|
|
||||||
return canmove;
|
return canmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +54,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
caninteract &= actionblockercomponents.CanInteract();
|
caninteract &= actionblockercomponents.CanInteract();
|
||||||
}
|
}
|
||||||
|
|
||||||
return caninteract;
|
return caninteract;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +65,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
canuse &= actionblockercomponents.CanUse();
|
canuse &= actionblockercomponents.CanUse();
|
||||||
}
|
}
|
||||||
|
|
||||||
return canuse;
|
return canuse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +76,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
canthrow &= actionblockercomponents.CanThrow();
|
canthrow &= actionblockercomponents.CanThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
return canthrow;
|
return canthrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +87,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
canspeak &= actionblockercomponents.CanSpeak();
|
canspeak &= actionblockercomponents.CanSpeak();
|
||||||
}
|
}
|
||||||
|
|
||||||
return canspeak;
|
return canspeak;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +98,9 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
candrop &= actionblockercomponents.CanDrop();
|
candrop &= actionblockercomponents.CanDrop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return candrop;
|
return candrop;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanPickup(IEntity entity)
|
public static bool CanPickup(IEntity entity)
|
||||||
{
|
{
|
||||||
@@ -99,6 +109,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
canpickup &= actionblockercomponents.CanPickup();
|
canpickup &= actionblockercomponents.CanPickup();
|
||||||
}
|
}
|
||||||
|
|
||||||
return canpickup;
|
return canpickup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,5 +172,25 @@ namespace Content.Shared.GameObjects.EntitySystems
|
|||||||
|
|
||||||
return canchangedirection;
|
return canchangedirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool CanShiver(IEntity entity)
|
||||||
|
{
|
||||||
|
var canShiver = true;
|
||||||
|
foreach (var component in entity.GetAllComponents<IActionBlocker>())
|
||||||
|
{
|
||||||
|
canShiver &= component.CanShiver();
|
||||||
|
}
|
||||||
|
return canShiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanSweat(IEntity entity)
|
||||||
|
{
|
||||||
|
var canSweat = true;
|
||||||
|
foreach (var component in entity.GetAllComponents<IActionBlocker>())
|
||||||
|
{
|
||||||
|
canSweat &= component.CanSweat();
|
||||||
|
}
|
||||||
|
return canSweat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,12 +128,26 @@
|
|||||||
layer:
|
layer:
|
||||||
- Opaque
|
- Opaque
|
||||||
- MobImpassable
|
- MobImpassable
|
||||||
|
- type: AtmosExposed
|
||||||
|
- type: Temperature
|
||||||
|
heatDamageThreshold: 360
|
||||||
|
coldDamageThreshold: 260
|
||||||
|
currentTemperature: 310.15
|
||||||
|
specificHeat: 42
|
||||||
|
tempDamageCoefficient: 0.1
|
||||||
- type: BodyManager
|
- type: BodyManager
|
||||||
criticalThreshold: 100
|
criticalThreshold: 100
|
||||||
deadThreshold: 200
|
deadThreshold: 200
|
||||||
baseTemplate: bodyTemplate.Humanoid
|
baseTemplate: bodyTemplate.Humanoid
|
||||||
basePreset: bodyPreset.BasicHuman
|
basePreset: bodyPreset.BasicHuman
|
||||||
- type: Metabolism
|
- type: Metabolism
|
||||||
|
metabolismHeat: 5000
|
||||||
|
radiatedHeat: 400
|
||||||
|
implicitHeatRegulation: 5000
|
||||||
|
sweatHeatRegulation: 5000
|
||||||
|
shiveringHeatRegulation: 5000
|
||||||
|
normalBodyTemperature: 310.15
|
||||||
|
thermalRegulationTemperatureThreshold: 25
|
||||||
needsGases:
|
needsGases:
|
||||||
Oxygen: 0.006365740
|
Oxygen: 0.006365740
|
||||||
producesGases:
|
producesGases:
|
||||||
|
|||||||
Reference in New Issue
Block a user