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",
|
||||
"Destructible",
|
||||
"Temperature",
|
||||
"AtmosExposed",
|
||||
"Explosive",
|
||||
"OnUseTimerTrigger",
|
||||
"ToolboxElectricalFill",
|
||||
|
||||
@@ -19,9 +19,9 @@ namespace Content.Server.Atmos
|
||||
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)
|
||||
@@ -30,10 +30,10 @@ namespace Content.Server.Atmos
|
||||
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
|
||||
return !Equals(air = coordinates.GetTileAir()!, default);
|
||||
return !Equals(air = coordinates.GetTileAir(entityManager)!, default);
|
||||
}
|
||||
|
||||
public static TileAtmosphere? GetTileAtmosphere(this MapIndices indices, GridId gridId)
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Content.Server.Atmos
|
||||
public int AtmosCooldown { get; set; } = 0;
|
||||
|
||||
[ViewVariables]
|
||||
private float _temperature = Atmospherics.T20C;
|
||||
public float Temperature {get; private set; } = Atmospherics.T20C;
|
||||
|
||||
[ViewVariables]
|
||||
private float _temperatureArchived = Atmospherics.T20C;
|
||||
@@ -132,7 +132,7 @@ namespace Content.Server.Atmos
|
||||
{
|
||||
Air?.Archive();
|
||||
_archivedCycle = fireCount;
|
||||
_temperatureArchived = _temperature;
|
||||
_temperatureArchived = Temperature;
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
@@ -897,7 +897,7 @@ namespace Content.Server.Atmos
|
||||
other.TemperatureShareMutualSolid(this, ThermalConductivity);
|
||||
}
|
||||
|
||||
TemperatureExpose(null, _temperature, _gridAtmosphereComponent.GetVolumeForCells(1));
|
||||
TemperatureExpose(null, Temperature, _gridAtmosphereComponent.GetVolumeForCells(1));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -915,8 +915,8 @@ namespace Content.Server.Atmos
|
||||
|
||||
private void TemperatureShareOpenToSolid(TileAtmosphere other)
|
||||
{
|
||||
other._temperature =
|
||||
Air.TemperatureShare(other.ThermalConductivity, other._temperature, other.HeatCapacity);
|
||||
other.Temperature =
|
||||
Air.TemperatureShare(other.ThermalConductivity, other.Temperature, other.HeatCapacity);
|
||||
}
|
||||
|
||||
private void TemperatureShareMutualSolid(TileAtmosphere other, float conductionCoefficient)
|
||||
@@ -928,15 +928,15 @@ namespace Content.Server.Atmos
|
||||
var heat = conductionCoefficient * deltaTemperature *
|
||||
(HeatCapacity * other.HeatCapacity / (HeatCapacity + other.HeatCapacity));
|
||||
|
||||
_temperature -= heat / HeatCapacity;
|
||||
other._temperature += heat / other.HeatCapacity;
|
||||
Temperature -= heat / HeatCapacity;
|
||||
other.Temperature += heat / other.HeatCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
public void RadiateToSpace()
|
||||
{
|
||||
// Considering 0ºC as the break even point for radiation in and out.
|
||||
if (_temperature > Atmospherics.T0C)
|
||||
if (Temperature > Atmospherics.T0C)
|
||||
{
|
||||
// Hardcoded space temperature.
|
||||
var deltaTemperature = (_temperatureArchived - Atmospherics.TCMB);
|
||||
@@ -945,7 +945,7 @@ namespace Content.Server.Atmos
|
||||
var heat = ThermalConductivity * deltaTemperature * (HeatCapacity *
|
||||
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.Runtime.CompilerServices;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Atmos
|
||||
@@ -19,21 +17,14 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
[RegisterComponent]
|
||||
public class BarotraumaComponent : Component
|
||||
{
|
||||
[Robust.Shared.IoC.Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public override string Name => "Barotrauma";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Update(float frameTime)
|
||||
public void Update(float airPressure)
|
||||
{
|
||||
if (!Owner.TryGetComponent(out IDamageableComponent damageable)) return;
|
||||
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 lowPressureMultiplier = 1f;
|
||||
|
||||
@@ -43,8 +34,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
lowPressureMultiplier *= protection.LowPressureMultiplier;
|
||||
}
|
||||
|
||||
if (tile?.Air != null)
|
||||
pressure = MathF.Max(tile.Air.Pressure, 1f);
|
||||
var pressure = MathF.Max(airPressure, 1f);
|
||||
|
||||
switch (pressure)
|
||||
{
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
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.Chemistry;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -21,11 +26,16 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
||||
public class MetabolismComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
|
||||
public override string Name => "Metabolism";
|
||||
|
||||
private float _accumulatedFrameTime;
|
||||
|
||||
private bool _isShivering;
|
||||
private bool _isSweating;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] private int _suffocationDamage;
|
||||
|
||||
[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; }
|
||||
|
||||
/// <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;
|
||||
|
||||
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.ProducesGases, "producesGases", 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);
|
||||
}
|
||||
|
||||
@@ -152,6 +211,76 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
||||
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>
|
||||
/// Loops through each reagent in _internalSolution,
|
||||
/// and calls <see cref="IMetabolizable.Metabolize"/> for each of them.
|
||||
@@ -196,6 +325,12 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
||||
/// </param>
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
if (!Owner.TryGetComponent<IDamageableComponent>(out var damageable) ||
|
||||
damageable.CurrentDamageState == DamageState.Dead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_accumulatedFrameTime += frameTime;
|
||||
|
||||
if (_accumulatedFrameTime < 1)
|
||||
@@ -207,9 +342,9 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
||||
|
||||
ProcessGases(frameTime);
|
||||
ProcessNutrients(frameTime);
|
||||
ProcessThermalRegulation(frameTime);
|
||||
|
||||
if (Suffocating &&
|
||||
Owner.TryGetComponent(out IDamageableComponent damageable))
|
||||
if (Suffocating)
|
||||
{
|
||||
// damageable.ChangeDamage(DamageClass.Airloss, _suffocationDamage, false);
|
||||
}
|
||||
|
||||
@@ -1,61 +1,103 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.Maths;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Temperature
|
||||
{
|
||||
public interface ITemperatureComponent : IComponent
|
||||
{
|
||||
float CurrentTemperature { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles changing temperature,
|
||||
/// informing others of the current temperature,
|
||||
/// and taking fire damage from high temperature.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class TemperatureComponent : Component, ITemperatureComponent
|
||||
public class TemperatureComponent : Component
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Temperature";
|
||||
|
||||
//TODO: should be programmatic instead of how it currently is
|
||||
[ViewVariables] public float CurrentTemperature { get; private set; } = PhysicalConstants.ZERO_CELCIUS;
|
||||
[ViewVariables] public float CurrentTemperature { get => _currentTemperature; set => _currentTemperature = value; }
|
||||
|
||||
float _fireDamageThreshold = 0;
|
||||
float _fireDamageCoefficient = 1;
|
||||
[ViewVariables] public float HeatDamageThreshold => _heatDamageThreshold;
|
||||
[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)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _fireDamageThreshold, "firedamagethreshold", 0);
|
||||
serializer.DataField(ref _fireDamageCoefficient, "firedamagecoefficient", 1);
|
||||
serializer.DataField(ref _heatDamageThreshold, "heatDamageThreshold", 0);
|
||||
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 OnUpdate(float frameTime)
|
||||
public void Update()
|
||||
{
|
||||
var fireDamage =
|
||||
(int) Math.Floor(Math.Max(0, CurrentTemperature - _fireDamageThreshold) / _fireDamageCoefficient);
|
||||
|
||||
_secondsSinceLastDamageUpdate += frameTime;
|
||||
|
||||
Owner.TryGetComponent(out IDamageableComponent component);
|
||||
|
||||
while (_secondsSinceLastDamageUpdate >= 1)
|
||||
var tempDamage = 0;
|
||||
DamageType? damageType = null;
|
||||
if (CurrentTemperature >= _heatDamageThreshold)
|
||||
{
|
||||
component?.ChangeDamage(DamageType.Heat, fireDamage, false, null);
|
||||
_secondsSinceLastDamageUpdate -= 1;
|
||||
}
|
||||
}
|
||||
tempDamage = (int) Math.Floor((CurrentTemperature - _heatDamageThreshold) * _tempDamageCoefficient);
|
||||
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 Content.Server.Atmos;
|
||||
using Content.Server.Atmos.Reactions;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Shared.GameObjects.EntitySystems.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
@@ -64,8 +65,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery<IMapGridComponent, IGridAtmosphereComponent>())
|
||||
{
|
||||
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex))
|
||||
continue;
|
||||
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue;
|
||||
|
||||
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 CanChangeDirection() => true;
|
||||
|
||||
public bool CanShiver() => !Stunned;
|
||||
public bool CanSweat() => true;
|
||||
|
||||
#endregion
|
||||
|
||||
[ViewVariables]
|
||||
|
||||
@@ -69,5 +69,8 @@ namespace Content.Shared.GameObjects.Components.Mobs.State
|
||||
{
|
||||
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 CanEmote() => false;
|
||||
public bool CanAttack() => false;
|
||||
public bool CanShiver() => false;
|
||||
public bool CanSweat() => false;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using System.Linq;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Shared.GameObjects.EntitySystems
|
||||
@@ -24,6 +25,9 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
bool CanUnequip() => true;
|
||||
|
||||
bool CanChangeDirection() => true;
|
||||
|
||||
bool CanShiver() => true;
|
||||
bool CanSweat() => true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,6 +43,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
canmove &= actionblockercomponents.CanMove(); // Sets var to false if false
|
||||
}
|
||||
|
||||
return canmove;
|
||||
}
|
||||
|
||||
@@ -49,6 +54,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
caninteract &= actionblockercomponents.CanInteract();
|
||||
}
|
||||
|
||||
return caninteract;
|
||||
}
|
||||
|
||||
@@ -59,6 +65,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
canuse &= actionblockercomponents.CanUse();
|
||||
}
|
||||
|
||||
return canuse;
|
||||
}
|
||||
|
||||
@@ -69,6 +76,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
canthrow &= actionblockercomponents.CanThrow();
|
||||
}
|
||||
|
||||
return canthrow;
|
||||
}
|
||||
|
||||
@@ -79,6 +87,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
canspeak &= actionblockercomponents.CanSpeak();
|
||||
}
|
||||
|
||||
return canspeak;
|
||||
}
|
||||
|
||||
@@ -89,6 +98,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
candrop &= actionblockercomponents.CanDrop();
|
||||
}
|
||||
|
||||
return candrop;
|
||||
}
|
||||
|
||||
@@ -99,6 +109,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
canpickup &= actionblockercomponents.CanPickup();
|
||||
}
|
||||
|
||||
return canpickup;
|
||||
}
|
||||
|
||||
@@ -161,5 +172,25 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
|
||||
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:
|
||||
- Opaque
|
||||
- MobImpassable
|
||||
- type: AtmosExposed
|
||||
- type: Temperature
|
||||
heatDamageThreshold: 360
|
||||
coldDamageThreshold: 260
|
||||
currentTemperature: 310.15
|
||||
specificHeat: 42
|
||||
tempDamageCoefficient: 0.1
|
||||
- type: BodyManager
|
||||
criticalThreshold: 100
|
||||
deadThreshold: 200
|
||||
baseTemplate: bodyTemplate.Humanoid
|
||||
basePreset: bodyPreset.BasicHuman
|
||||
- type: Metabolism
|
||||
metabolismHeat: 5000
|
||||
radiatedHeat: 400
|
||||
implicitHeatRegulation: 5000
|
||||
sweatHeatRegulation: 5000
|
||||
shiveringHeatRegulation: 5000
|
||||
normalBodyTemperature: 310.15
|
||||
thermalRegulationTemperatureThreshold: 25
|
||||
needsGases:
|
||||
Oxygen: 0.006365740
|
||||
producesGases:
|
||||
|
||||
Reference in New Issue
Block a user