diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs
index af320568fa..7dea6c8738 100644
--- a/Content.Client/IgnoredComponents.cs
+++ b/Content.Client/IgnoredComponents.cs
@@ -12,6 +12,7 @@
"CloningPod",
"Destructible",
"Temperature",
+ "AtmosExposed",
"Explosive",
"OnUseTimerTrigger",
"ToolboxElectricalFill",
diff --git a/Content.Server/Atmos/AtmosHelpers.cs b/Content.Server/Atmos/AtmosHelpers.cs
index 4e0d313d89..e7e8371804 100644
--- a/Content.Server/Atmos/AtmosHelpers.cs
+++ b/Content.Server/Atmos/AtmosHelpers.cs
@@ -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)
diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs
index eba6ad9c20..899dca18be 100644
--- a/Content.Server/Atmos/TileAtmosphere.cs
+++ b/Content.Server/Atmos/TileAtmosphere.cs
@@ -49,7 +49,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;
@@ -138,7 +138,7 @@ namespace Content.Server.Atmos
{
Air?.Archive();
_archivedCycle = fireCount;
- _temperatureArchived = _temperature;
+ _temperatureArchived = Temperature;
}
public void HotspotExpose(float exposedTemperature, float exposedVolume, bool soh = false)
@@ -875,10 +875,10 @@ namespace Content.Server.Atmos
// Conduct with air on my tile if I have it
if (!BlocksAllAir)
{
- _temperature = Air.TemperatureShare(ThermalConductivity, _temperature, HeatCapacity);
+ Temperature = Air.TemperatureShare(ThermalConductivity, Temperature, HeatCapacity);
}
- FinishSuperconduction(BlocksAllAir ? _temperature : Air.Temperature);
+ FinishSuperconduction(BlocksAllAir ? Temperature : Air.Temperature);
}
private void FinishSuperconduction(float temperature)
@@ -903,7 +903,7 @@ namespace Content.Server.Atmos
other.TemperatureShareMutualSolid(this, ThermalConductivity);
}
- TemperatureExpose(null, _temperature, _gridAtmosphereComponent.GetVolumeForCells(1));
+ TemperatureExpose(null, Temperature, _gridAtmosphereComponent.GetVolumeForCells(1));
return;
}
@@ -921,8 +921,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)
@@ -934,15 +934,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);
@@ -951,7 +951,7 @@ namespace Content.Server.Atmos
var heat = ThermalConductivity * deltaTemperature * (HeatCapacity *
Atmospherics.HeatCapacityVacuum / (HeatCapacity + Atmospherics.HeatCapacityVacuum));
- _temperature -= heat;
+ Temperature -= heat;
}
}
}
diff --git a/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs b/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs
new file mode 100644
index 0000000000..f5bfde7271
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs
@@ -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
+{
+ ///
+ /// Represents that entity can be exposed to Atmo
+ ///
+ [RegisterComponent]
+ public class AtmosExposedComponent
+ : Component
+ {
+ public override string Name => "AtmosExposed";
+
+ public void Update(TileAtmosphere tile, float timeDelta)
+ {
+ if (Owner.TryGetComponent(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(out var barotraumaComponent))
+ {
+ barotraumaComponent.Update(tile.Air?.Pressure ?? 0);
+ }
+
+ }
+
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs b/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
index d877165791..249df1639f 100644
--- a/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
+++ b/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
@@ -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().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)
{
diff --git a/Content.Server/GameObjects/Components/AtmosPlaqueComponent.cs b/Content.Server/GameObjects/Components/AtmosPlaqueComponent.cs
new file mode 100644
index 0000000000..e372c4c5f4
--- /dev/null
+++ b/Content.Server/GameObjects/Components/AtmosPlaqueComponent.cs
@@ -0,0 +1,109 @@
+using Robust.Server.GameObjects;
+using Robust.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.Random;
+using Robust.Shared.IoC;
+using Robust.Shared.Serialization;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.GameObjects.Components
+{
+ [RegisterComponent]
+ public sealed class AtmosPlaqueComponent : Component, IMapInit
+ {
+ private PlaqueType _type;
+ public override string Name => "AtmosPlaque";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public PlaqueType Type
+ {
+ get => _type;
+ set
+ {
+ _type = value;
+ UpdateSign();
+ }
+ }
+
+ public void MapInit()
+ {
+ var random = IoCManager.Resolve();
+ var rand = random.Next(100);
+ // Let's not pad ourselves on the back too hard.
+ // 1% chance of zumos
+ if (rand == 0) Type = PlaqueType.Zumos;
+ // 9% FEA
+ else if (rand <= 10) Type = PlaqueType.Fea;
+ // 45% ZAS
+ else if (rand <= 55) Type = PlaqueType.Zas;
+ // 45% LINDA
+ else Type = PlaqueType.Linda;
+ }
+
+ protected override void Startup()
+ {
+ base.Startup();
+
+ UpdateSign();
+ }
+
+ private void UpdateSign()
+ {
+ if (!Running)
+ {
+ return;
+ }
+
+ Owner.Description = _type switch
+ {
+ PlaqueType.Zumos =>
+ "This plaque commemorates the rise of the Atmos ZUM division. May they carry the torch that the Atmos ZAS, LINDA and FEA divisions left behind.",
+ PlaqueType.Fea =>
+ "This plaque commemorates the fall of the Atmos FEA division. For all the charred, dizzy, and brittle men who have died in its hands.",
+ PlaqueType.Linda =>
+ "This plaque commemorates the fall of the Atmos LINDA division. For all the charred, dizzy, and brittle men who have died in its hands.",
+ PlaqueType.Zas =>
+ "This plaque commemorates the fall of the Atmos ZAS division. For all the charred, dizzy, and brittle men who have died in its hands.",
+ PlaqueType.Unset => "Uhm"
+ };
+
+ Owner.Name = _type switch
+ {
+ PlaqueType.Zumos =>
+ "ZUM Atmospherics Division plaque",
+ PlaqueType.Fea =>
+ "FEA Atmospherics Division plaque",
+ PlaqueType.Linda =>
+ "LINDA Atmospherics Division plaque",
+ PlaqueType.Zas =>
+ "ZAS Atmospherics Division plaque",
+ PlaqueType.Unset => "Uhm"
+ };
+
+ if (Owner.TryGetComponent(out SpriteComponent sprite))
+ {
+ var state = _type == PlaqueType.Zumos ? "zumosplaque" : "atmosplaque";
+
+ sprite.LayerSetState(0, state);
+ }
+ }
+
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+
+ serializer.DataField(ref _type, "plaqueType", PlaqueType.Unset);
+ }
+
+ public enum PlaqueType
+ {
+ Unset = 0,
+ Zumos,
+ Fea,
+ Linda,
+ Zas
+ }
+ }
+}
+
+// If you get the ZUM plaque it means your round will be blessed with good engineering luck.
diff --git a/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs b/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs
index d9c1051e27..45fb5e2e11 100644
--- a/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs
+++ b/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs
@@ -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 NeedsGases { get; set; }
@@ -34,6 +44,47 @@ namespace Content.Server.GameObjects.Components.Metabolism
[ViewVariables] public Dictionary DeficitGases { get; set; }
+ ///
+ /// Heat generated due to metabolism. It's generated via metabolism
+ ///
+ [ViewVariables]
+ public float MetabolismHeat { get; private set; }
+
+ ///
+ /// Heat output via radiation.
+ ///
+ [ViewVariables]
+ public float RadiatedHeat { get; private set; }
+
+ ///
+ /// Maximum heat regulated via sweat
+ ///
+ [ViewVariables]
+ public float SweatHeatRegulation { get; private set; }
+
+ ///
+ /// Maximum heat regulated via shivering
+ ///
+ [ViewVariables]
+ public float ShiveringHeatRegulation { get; private set; }
+
+ ///
+ /// Amount of heat regulation that represents thermal regulation processes not
+ /// explicitly coded.
+ ///
+ public float ImplicitHeatRegulation { get; private set; }
+
+ ///
+ /// Normal body temperature
+ ///
+ [ViewVariables]
+ public float NormalBodyTemperature { get; private set; }
+
+ ///
+ /// Deviation from normal temperature for body to start thermal regulation
+ ///
+ 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());
serializer.DataField(this, b => b.ProducesGases, "producesGases", new Dictionary());
serializer.DataField(this, b => b.DeficitGases, "deficitGases", new Dictionary());
+ 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();
}
+ ///
+ /// Process thermal regulation
+ ///
+ ///
+ 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));
+ }
+ }
+
+
///
/// Loops through each reagent in _internalSolution,
/// and calls for each of them.
@@ -196,6 +325,12 @@ namespace Content.Server.GameObjects.Components.Metabolism
///
public void Update(float frameTime)
{
+ if (!Owner.TryGetComponent(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);
}
diff --git a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs
index 3c80f17bca..4828df6dee 100644
--- a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs
+++ b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs
@@ -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; }
- }
-
///
/// Handles changing temperature,
/// informing others of the current temperature,
/// and taking fire damage from high temperature.
///
[RegisterComponent]
- public class TemperatureComponent : Component, ITemperatureComponent
+ public class TemperatureComponent : Component
{
///
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(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);
}
- ///
- 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}");
}
+
+ ///
+ /// Forcefully give heat to this component
+ ///
+ ///
+ public void ReceiveHeat(float heatAmount)
+ {
+ CurrentTemperature += heatAmount / HeatCapacity;
+ }
+
+ ///
+ /// Forcefully remove heat from this component
+ ///
+ ///
+ public void RemoveHeat(float heatAmount)
+ {
+ CurrentTemperature -= heatAmount / HeatCapacity;
+ }
+
}
}
diff --git a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs
new file mode 100644
index 0000000000..7f620ad222
--- /dev/null
+++ b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs
@@ -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();
+ // creadth: everything exposable by atmo should be updated as well
+ foreach (var atmosExposedComponent in EntityManager.ComponentManager.EntityQuery())
+ {
+ var tile = atmosExposedComponent.Owner.Transform.Coordinates.GetTileAtmosphere(_entityManager);
+ if (tile == null) continue;
+ atmosExposedComponent.Update(tile, _lastUpdate);
+ }
+
+ _lastUpdate = 0;
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs
index 84bce7a646..309d8e02ca 100644
--- a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs
+++ b/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs
@@ -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())
{
- if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex))
- continue;
+ if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue;
gridAtmosphereComponent.Update(frameTime);
}
diff --git a/Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs b/Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs
deleted file mode 100644
index d607c3d984..0000000000
--- a/Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs
+++ /dev/null
@@ -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;
-
- ///
- public override void Update(float frameTime)
- {
- _timer += frameTime;
-
- if (_timer < TimePerUpdate) return;
-
- _timer = 0f;
-
- foreach (var barotraumaComp in ComponentManager.EntityQuery())
- {
- barotraumaComp.Update(frameTime);
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs b/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs
deleted file mode 100644
index f03b240a0b..0000000000
--- a/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs
+++ /dev/null
@@ -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())
- {
- comp.OnUpdate(frameTime);
- }
- }
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs
index 1d324ba7d4..cfa2268d2b 100644
--- a/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs
+++ b/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs
@@ -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]
diff --git a/Content.Shared/GameObjects/Components/Mobs/State/SharedDeadState.cs b/Content.Shared/GameObjects/Components/Mobs/State/SharedDeadState.cs
index 6dc85a07cf..43887b878b 100644
--- a/Content.Shared/GameObjects/Components/Mobs/State/SharedDeadState.cs
+++ b/Content.Shared/GameObjects/Components/Mobs/State/SharedDeadState.cs
@@ -69,5 +69,8 @@ namespace Content.Shared.GameObjects.Components.Mobs.State
{
return false;
}
+
+ public bool CanShiver() => false;
+ public bool CanSweat() => false;
}
}
diff --git a/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs b/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs
index e9a029271c..797a1ac08d 100644
--- a/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs
+++ b/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs
@@ -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]
diff --git a/Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs b/Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs
index e7a32bf4fe..f3db58a623 100644
--- a/Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs
+++ b/Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs
@@ -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;
}
///
@@ -35,10 +39,11 @@ namespace Content.Shared.GameObjects.EntitySystems
public static bool CanMove(IEntity entity)
{
bool canmove = true;
- foreach(var actionblockercomponents in entity.GetAllComponents())
+ foreach (var actionblockercomponents in entity.GetAllComponents())
{
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,8 +98,9 @@ namespace Content.Shared.GameObjects.EntitySystems
{
candrop &= actionblockercomponents.CanDrop();
}
+
return candrop;
- }
+ }
public static bool CanPickup(IEntity entity)
{
@@ -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())
+ {
+ canShiver &= component.CanShiver();
+ }
+ return canShiver;
+ }
+
+ public static bool CanSweat(IEntity entity)
+ {
+ var canSweat = true;
+ foreach (var component in entity.GetAllComponents())
+ {
+ canSweat &= component.CanSweat();
+ }
+ return canSweat;
+ }
}
}
diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml
index 2b0fa6bbe4..eaaf44c683 100644
--- a/Resources/Maps/saltern.yml
+++ b/Resources/Maps/saltern.yml
@@ -1263,7 +1263,7 @@ entities:
type: Content.Server.GameObjects.ContainerSlot
type: ContainerContainer
- uid: 137
- type: PlaqueZum
+ type: PlaqueAtmos
components:
- parent: 857
pos: 33.498077,11.399912
diff --git a/Resources/Prototypes/Entities/Constructible/Walls/atmos_plaque.yml b/Resources/Prototypes/Entities/Constructible/Walls/atmos_plaque.yml
new file mode 100644
index 0000000000..499f0ca0b0
--- /dev/null
+++ b/Resources/Prototypes/Entities/Constructible/Walls/atmos_plaque.yml
@@ -0,0 +1,22 @@
+- type: entity
+ parent: BaseSign
+ id: PlaqueAtmos
+ name: Atmos Plaque
+ components:
+ - type: Collidable
+ shapes:
+ - !type:PhysShapeAabb
+ bounds: "-0.3,-0.3,0.3,0.3"
+ layer:
+ - Opaque
+ - Impassable
+ - MobImpassable
+ - VaultImpassable
+ - SmallImpassable
+ - Clickable
+
+ - type: Icon
+ state: atmosplaque
+ - type: Sprite
+ state: atmosplaque
+ - type: AtmosPlaque
diff --git a/Resources/Prototypes/Entities/Constructible/Walls/signs.yml b/Resources/Prototypes/Entities/Constructible/Walls/signs.yml
index 222ff68297..36d2b59214 100644
--- a/Resources/Prototypes/Entities/Constructible/Walls/signs.yml
+++ b/Resources/Prototypes/Entities/Constructible/Walls/signs.yml
@@ -974,50 +974,6 @@
- type: Icon
state: atmos_waste
-- type: entity
- parent: BaseSign
- id: PlaqueZum
- name: zumos plaque
- description: "This plaque commemorates the rise of the Atmos ZUM division. May they carry the torch that the Atmos ZAS, LINDA and FEA divisions left behind."
- components:
- - type: Collidable
- shapes:
- - !type:PhysShapeAabb
- bounds: "-0.3,-0.3,0.3,0.3"
- layer:
- - Opaque
- - Impassable
- - MobImpassable
- - VaultImpassable
- - SmallImpassable
- - Clickable
- - type: Sprite
- state: zumosplaque
- - type: Icon
- state: zumosplaque
-
-- type: entity
- parent: BaseSign
- id: PlaqueAtmos
- name: atmos plaque
- description: "This plaque commemorates the fall of the Atmos FEA division. For all the charred, dizzy, and brittle men who have died in its hands."
- components:
- - type: Collidable
- shapes:
- - !type:PhysShapeAabb
- bounds: "-0.3,-0.3,0.3,0.3"
- layer:
- - Opaque
- - Impassable
- - MobImpassable
- - VaultImpassable
- - SmallImpassable
- - Clickable
- - type: Sprite
- state: atmosplaque
- - type: Icon
- state: atmosplaque
-
- type: entity
parent: BaseSign
id: SignSmoking
diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml
index e672beebd5..24a01b43c6 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/human.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml
@@ -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:
diff --git a/RobustToolbox b/RobustToolbox
index a19e12e693..9cc9b68e09 160000
--- a/RobustToolbox
+++ b/RobustToolbox
@@ -1 +1 @@
-Subproject commit a19e12e6935b2368b6dc986ba369a4e23a89552c
+Subproject commit 9cc9b68e09b6512e5188c1478456dc1d1fd92b13