]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Temperature refactor (#20662)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Mon, 2 Oct 2023 14:44:05 +0000 (15:44 +0100)
committerGitHub <noreply@github.com>
Mon, 2 Oct 2023 14:44:05 +0000 (07:44 -0700)
Co-authored-by: deltanedas <@deltanedas:kde.org>
Content.Server/Temperature/Components/ContainerTemperatureDamageThresholdsComponent.cs
Content.Server/Temperature/Components/TemperatureComponent.cs
Content.Server/Temperature/Systems/TemperatureSystem.cs

index ae8acc49ef62972c4a93fc92f4008b88611e16c2..024b8a013b3a728e887c406ff6b81934e45617bf 100644 (file)
@@ -3,11 +3,9 @@
 [RegisterComponent]
 public sealed partial class ContainerTemperatureDamageThresholdsComponent: Component
 {
-    [DataField("heatDamageThreshold")]
-    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
     public float? HeatDamageThreshold;
 
-    [DataField("coldDamageThreshold")]
-    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
     public float? ColdDamageThreshold;
 }
index 6ace329426f9a0fbec63c9d96a29ecf35c1f28fe..7330ebf9ba5b3defa0ed81da36847bfefc2f4287 100644 (file)
@@ -4,84 +4,80 @@ using Content.Shared.FixedPoint;
 using Robust.Shared.Physics;
 using Robust.Shared.Physics.Components;
 
-namespace Content.Server.Temperature.Components
+namespace Content.Server.Temperature.Components;
+
+/// <summary>
+/// Handles changing temperature,
+/// informing others of the current temperature,
+/// and taking fire damage from high temperature.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TemperatureComponent : Component
 {
-    /// <summary>
-    /// Handles changing temperature,
-    /// informing others of the current temperature,
-    /// and taking fire damage from high temperature.
-    /// </summary>
-    [RegisterComponent]
-    public sealed partial class TemperatureComponent : Component
-    {
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("currentTemperature")]
-        public float CurrentTemperature { get; set; } = Atmospherics.T20C;
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float CurrentTemperature = Atmospherics.T20C;
 
-        [DataField("heatDamageThreshold")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float HeatDamageThreshold = 360f;
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float HeatDamageThreshold = 360f;
 
-        [DataField("coldDamageThreshold")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float ColdDamageThreshold = 260f;
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float ColdDamageThreshold = 260f;
 
-        /// <summary>
-        /// Overrides HeatDamageThreshold if the entity's within a parent with the TemperatureDamageThresholdsComponent component.
-        /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float? ParentHeatDamageThreshold;
+    /// <summary>
+    /// Overrides HeatDamageThreshold if the entity's within a parent with the TemperatureDamageThresholdsComponent component.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float? ParentHeatDamageThreshold;
 
-        /// <summary>
-        /// Overrides ColdDamageThreshold if the entity's within a parent with the TemperatureDamageThresholdsComponent component.
-        /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float? ParentColdDamageThreshold;
+    /// <summary>
+    /// Overrides ColdDamageThreshold if the entity's within a parent with the TemperatureDamageThresholdsComponent component.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float? ParentColdDamageThreshold;
 
-        [DataField("specificHeat")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float SpecificHeat = 50f;
+    /// <summary>
+    /// Heat capacity per kg of mass.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float SpecificHeat = 50f;
 
-        /// <summary>
-        ///     How well does the air surrounding you merge into your body temperature?
-        /// </summary>
-        [DataField("atmosTemperatureTransferEfficiency")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float AtmosTemperatureTransferEfficiency = 0.1f;
+    /// <summary>
+    /// How well does the air surrounding you merge into your body temperature?
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float AtmosTemperatureTransferEfficiency = 0.1f;
 
-        [ViewVariables] public float HeatCapacity
+    [ViewVariables] public float HeatCapacity
+    {
+        get
         {
-            get
+            if (IoCManager.Resolve<IEntityManager>().TryGetComponent<PhysicsComponent>(Owner, out var physics) && physics.FixturesMass != 0)
             {
-                if (IoCManager.Resolve<IEntityManager>().TryGetComponent<PhysicsComponent>(Owner, out var physics) && physics.FixturesMass != 0)
-                {
-                    return SpecificHeat * physics.FixturesMass;
-                }
-
-                return Atmospherics.MinimumHeatCapacity;
+                return SpecificHeat * physics.FixturesMass;
             }
+
+            return Atmospherics.MinimumHeatCapacity;
         }
+    }
 
-        [DataField("coldDamage")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public DamageSpecifier ColdDamage = new();
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public DamageSpecifier ColdDamage = new();
 
-        [DataField("heatDamage")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public DamageSpecifier HeatDamage = new();
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public DamageSpecifier HeatDamage = new();
 
-        /// <summary>
-        ///     Temperature won't do more than this amount of damage per second.
-        ///
-        ///     Okay it genuinely reaches this basically immediately for a plasma fire.
-        /// </summary>
-        [DataField("damageCap")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public FixedPoint2 DamageCap = FixedPoint2.New(8);
+    /// <summary>
+    /// Temperature won't do more than this amount of damage per second.
+    /// </summary>
+    /// <remarks>
+    /// Okay it genuinely reaches this basically immediately for a plasma fire.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public FixedPoint2 DamageCap = FixedPoint2.New(8);
 
-        /// <summary>
-        ///     Used to keep track of when damage starts/stops. Useful for logs.
-        /// </summary>
-        public bool TakingDamage = false;
-    }
+    /// <summary>
+    /// Used to keep track of when damage starts/stops. Useful for logs.
+    /// </summary>
+    [DataField]
+    public bool TakingDamage = false;
 }
index 9c5675486166876ec05f6fe3c1eb5da3ef8514c0..4796704d27be1ec69432e882a8428dc5a63a4135 100644 (file)
@@ -1,6 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
 using Content.Server.Administration.Logs;
 using Content.Server.Atmos.Components;
 using Content.Server.Atmos.EntitySystems;
@@ -13,351 +10,349 @@ using Content.Shared.Inventory;
 using Content.Shared.Rejuvenate;
 using Content.Shared.Temperature;
 using Robust.Server.GameObjects;
+using System.Linq;
 
-namespace Content.Server.Temperature.Systems
-{
-    public sealed class TemperatureSystem : EntitySystem
-    {
-        [Dependency] private readonly TransformSystem _transformSystem = default!;
-        [Dependency] private readonly DamageableSystem _damageableSystem = default!;
-        [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
-        [Dependency] private readonly AlertsSystem _alertsSystem = default!;
-        [Dependency] private readonly IAdminLogManager _adminLogger = default!;
-
-        /// <summary>
-        ///     All the components that will have their damage updated at the end of the tick.
-        ///     This is done because both AtmosExposed and Flammable call ChangeHeat in the same tick, meaning
-        ///     that we need some mechanism to ensure it doesn't double dip on damage for both calls.
-        /// </summary>
-        public HashSet<TemperatureComponent> ShouldUpdateDamage = new();
+namespace Content.Server.Temperature.Systems;
 
-        public float UpdateInterval = 1.0f;
+public sealed class TemperatureSystem : EntitySystem
+{
+    [Dependency] private readonly AlertsSystem _alerts = default!;
+    [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
+    [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly TransformSystem _transform = default!;
 
-        private float _accumulatedFrametime;
+    /// <summary>
+    ///     All the components that will have their damage updated at the end of the tick.
+    ///     This is done because both AtmosExposed and Flammable call ChangeHeat in the same tick, meaning
+    ///     that we need some mechanism to ensure it doesn't double dip on damage for both calls.
+    /// </summary>
+    public HashSet<TemperatureComponent> ShouldUpdateDamage = new();
 
-        public override void Initialize()
-        {
-            SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
-            SubscribeLocalEvent<TemperatureComponent, AtmosExposedUpdateEvent>(OnAtmosExposedUpdate);
-            SubscribeLocalEvent<TemperatureComponent, RejuvenateEvent>(OnRejuvenate);
-            SubscribeLocalEvent<AlertsComponent, OnTemperatureChangeEvent>(ServerAlert);
-            SubscribeLocalEvent<TemperatureProtectionComponent, InventoryRelayedEvent<ModifyChangedTemperatureEvent>>(
-                OnTemperatureChangeAttempt);
-
-            // Allows overriding thresholds based on the parent's thresholds.
-            SubscribeLocalEvent<TemperatureComponent, EntParentChangedMessage>(OnParentChange);
-            SubscribeLocalEvent<ContainerTemperatureDamageThresholdsComponent, ComponentStartup>(
-                OnParentThresholdStartup);
-            SubscribeLocalEvent<ContainerTemperatureDamageThresholdsComponent, ComponentShutdown>(
-                OnParentThresholdShutdown);
-        }
+    public float UpdateInterval = 1.0f;
 
-        public override void Update(float frameTime)
-        {
-            base.Update(frameTime);
+    private float _accumulatedFrametime;
 
-            _accumulatedFrametime += frameTime;
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
+        SubscribeLocalEvent<TemperatureComponent, AtmosExposedUpdateEvent>(OnAtmosExposedUpdate);
+        SubscribeLocalEvent<TemperatureComponent, RejuvenateEvent>(OnRejuvenate);
+        SubscribeLocalEvent<AlertsComponent, OnTemperatureChangeEvent>(ServerAlert);
+        SubscribeLocalEvent<TemperatureProtectionComponent, InventoryRelayedEvent<ModifyChangedTemperatureEvent>>(
+            OnTemperatureChangeAttempt);
+
+        // Allows overriding thresholds based on the parent's thresholds.
+        SubscribeLocalEvent<TemperatureComponent, EntParentChangedMessage>(OnParentChange);
+        SubscribeLocalEvent<ContainerTemperatureDamageThresholdsComponent, ComponentStartup>(
+            OnParentThresholdStartup);
+        SubscribeLocalEvent<ContainerTemperatureDamageThresholdsComponent, ComponentShutdown>(
+            OnParentThresholdShutdown);
+    }
 
-            if (_accumulatedFrametime < UpdateInterval)
-                return;
-            _accumulatedFrametime -= UpdateInterval;
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
 
-            if (!ShouldUpdateDamage.Any())
-                return;
+        _accumulatedFrametime += frameTime;
 
-            foreach (var comp in ShouldUpdateDamage)
-            {
-                MetaDataComponent? metaData = null;
+        if (_accumulatedFrametime < UpdateInterval)
+            return;
+        _accumulatedFrametime -= UpdateInterval;
 
-                var uid = comp.Owner;
-                if (Deleted(uid, metaData) || Paused(uid, metaData))
-                    continue;
+        if (!ShouldUpdateDamage.Any())
+            return;
 
-                ChangeDamage(uid, comp);
-            }
+        foreach (var comp in ShouldUpdateDamage)
+        {
+            MetaDataComponent? metaData = null;
 
-            ShouldUpdateDamage.Clear();
-        }
+            var uid = comp.Owner;
+            if (Deleted(uid, metaData) || Paused(uid, metaData))
+                continue;
 
-        public void ForceChangeTemperature(EntityUid uid, float temp, TemperatureComponent? temperature = null)
-        {
-            if (!Resolve(uid, ref temperature))
-                return;
-
-            float lastTemp = temperature.CurrentTemperature;
-            float delta = temperature.CurrentTemperature - temp;
-            temperature.CurrentTemperature = temp;
-            RaiseLocalEvent(uid, new OnTemperatureChangeEvent(temperature.CurrentTemperature, lastTemp, delta),
-                true);
+            ChangeDamage(uid, comp);
         }
 
-        public void ChangeHeat(EntityUid uid, float heatAmount, bool ignoreHeatResistance = false,
-            TemperatureComponent? temperature = null)
-        {
-            if (Resolve(uid, ref temperature))
-            {
-                if (!ignoreHeatResistance)
-                {
-                    var ev = new ModifyChangedTemperatureEvent(heatAmount);
-                    RaiseLocalEvent(uid, ev, false);
-                    heatAmount = ev.TemperatureDelta;
-                }
+        ShouldUpdateDamage.Clear();
+    }
 
-                float lastTemp = temperature.CurrentTemperature;
-                temperature.CurrentTemperature += heatAmount / temperature.HeatCapacity;
-                float delta = temperature.CurrentTemperature - lastTemp;
+    public void ForceChangeTemperature(EntityUid uid, float temp, TemperatureComponent? temperature = null)
+    {
+        if (!Resolve(uid, ref temperature))
+            return;
+
+        float lastTemp = temperature.CurrentTemperature;
+        float delta = temperature.CurrentTemperature - temp;
+        temperature.CurrentTemperature = temp;
+        RaiseLocalEvent(uid, new OnTemperatureChangeEvent(temperature.CurrentTemperature, lastTemp, delta),
+            true);
+    }
 
-                RaiseLocalEvent(uid, new OnTemperatureChangeEvent(temperature.CurrentTemperature, lastTemp, delta),
-                    true);
-            }
-        }
+    public void ChangeHeat(EntityUid uid, float heatAmount, bool ignoreHeatResistance = false,
+        TemperatureComponent? temperature = null)
+    {
+        if (!Resolve(uid, ref temperature))
+            return;
 
-        private void OnAtmosExposedUpdate(EntityUid uid, TemperatureComponent temperature,
-            ref AtmosExposedUpdateEvent args)
+        if (!ignoreHeatResistance)
         {
-            var transform = args.Transform;
-
-            if (transform.MapUid == null)
-                return;
+            var ev = new ModifyChangedTemperatureEvent(heatAmount);
+            RaiseLocalEvent(uid, ev, false);
+            heatAmount = ev.TemperatureDelta;
+        }
 
-            var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
+        float lastTemp = temperature.CurrentTemperature;
+        temperature.CurrentTemperature += heatAmount / temperature.HeatCapacity;
+        float delta = temperature.CurrentTemperature - lastTemp;
 
-            var temperatureDelta = args.GasMixture.Temperature - temperature.CurrentTemperature;
-            var tileHeatCapacity =
-                _atmosphereSystem.GetTileHeatCapacity(transform.GridUid, transform.MapUid.Value, position);
-            var heat = temperatureDelta * (tileHeatCapacity * temperature.HeatCapacity /
-                                           (tileHeatCapacity + temperature.HeatCapacity));
-            ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature);
-        }
+        RaiseLocalEvent(uid, new OnTemperatureChangeEvent(temperature.CurrentTemperature, lastTemp, delta), true);
+    }
 
-        private void OnRejuvenate(EntityUid uid, TemperatureComponent comp, RejuvenateEvent args)
-        {
-            ForceChangeTemperature(uid, Atmospherics.T20C, comp);
-        }
+    private void OnAtmosExposedUpdate(EntityUid uid, TemperatureComponent temperature,
+        ref AtmosExposedUpdateEvent args)
+    {
+        var transform = args.Transform;
+        if (transform.MapUid == null)
+            return;
+
+        var position = _transform.GetGridOrMapTilePosition(uid, transform);
+
+        var temperatureDelta = args.GasMixture.Temperature - temperature.CurrentTemperature;
+        var tileHeatCapacity =
+            _atmosphere.GetTileHeatCapacity(transform.GridUid, transform.MapUid.Value, position);
+        var heat = temperatureDelta * (tileHeatCapacity * temperature.HeatCapacity /
+                                       (tileHeatCapacity + temperature.HeatCapacity));
+        ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature);
+    }
 
-        private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args)
-        {
-            switch (args.CurrentTemperature)
-            {
-                // Cold strong.
-                case <= 260:
-                    _alertsSystem.ShowAlert(uid, AlertType.Cold, 3);
-                    break;
-
-                // Cold mild.
-                case <= 280 and > 260:
-                    _alertsSystem.ShowAlert(uid, AlertType.Cold, 2);
-                    break;
-
-                // Cold weak.
-                case <= 292 and > 280:
-                    _alertsSystem.ShowAlert(uid, AlertType.Cold, 1);
-                    break;
-
-                // Safe.
-                case <= 327 and > 292:
-                    _alertsSystem.ClearAlertCategory(uid, AlertCategory.Temperature);
-                    break;
-
-                // Heat weak.
-                case <= 335 and > 327:
-                    _alertsSystem.ShowAlert(uid, AlertType.Hot, 1);
-                    break;
-
-                // Heat mild.
-                case <= 360 and > 335:
-                    _alertsSystem.ShowAlert(uid, AlertType.Hot, 2);
-                    break;
-
-                // Heat strong.
-                case > 360:
-                    _alertsSystem.ShowAlert(uid, AlertType.Hot, 3);
-                    break;
-            }
-        }
+    private void OnRejuvenate(EntityUid uid, TemperatureComponent comp, RejuvenateEvent args)
+    {
+        ForceChangeTemperature(uid, Atmospherics.T20C, comp);
+    }
 
-        private void EnqueueDamage(EntityUid uid, TemperatureComponent component, OnTemperatureChangeEvent args)
+    private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args)
+    {
+        switch (args.CurrentTemperature)
         {
-            ShouldUpdateDamage.Add(component);
+            // Cold strong.
+            case <= 260:
+                _alerts.ShowAlert(uid, AlertType.Cold, 3);
+                break;
+
+            // Cold mild.
+            case <= 280 and > 260:
+                _alerts.ShowAlert(uid, AlertType.Cold, 2);
+                break;
+
+            // Cold weak.
+            case <= 292 and > 280:
+                _alerts.ShowAlert(uid, AlertType.Cold, 1);
+                break;
+
+            // Safe.
+            case <= 327 and > 292:
+                _alerts.ClearAlertCategory(uid, AlertCategory.Temperature);
+                break;
+
+            // Heat weak.
+            case <= 335 and > 327:
+                _alerts.ShowAlert(uid, AlertType.Hot, 1);
+                break;
+
+            // Heat mild.
+            case <= 360 and > 335:
+                _alerts.ShowAlert(uid, AlertType.Hot, 2);
+                break;
+
+            // Heat strong.
+            case > 360:
+                _alerts.ShowAlert(uid, AlertType.Hot, 3);
+                break;
         }
+    }
 
-        private void ChangeDamage(EntityUid uid, TemperatureComponent temperature)
-        {
-            if (!HasComp<DamageableComponent>(uid))
-                return;
-
-            // See this link for where the scaling func comes from:
-            // https://www.desmos.com/calculator/0vknqtdvq9
-            // Based on a logistic curve, which caps out at MaxDamage
-            var heatK = 0.005;
-            var a = 1;
-            var y = temperature.DamageCap;
-            var c = y * 2;
+    private void EnqueueDamage(EntityUid uid, TemperatureComponent component, OnTemperatureChangeEvent args)
+    {
+        ShouldUpdateDamage.Add(component);
+    }
 
-            var heatDamageThreshold = temperature.ParentHeatDamageThreshold ?? temperature.HeatDamageThreshold;
-            var coldDamageThreshold = temperature.ParentColdDamageThreshold ?? temperature.ColdDamageThreshold;
+    private void ChangeDamage(EntityUid uid, TemperatureComponent temperature)
+    {
+        if (!HasComp<DamageableComponent>(uid))
+            return;
 
-            if (temperature.CurrentTemperature >= heatDamageThreshold)
-            {
-                if (!temperature.TakingDamage)
-                {
-                    _adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} started taking high temperature damage");
-                    temperature.TakingDamage = true;
-                }
+        // See this link for where the scaling func comes from:
+        // https://www.desmos.com/calculator/0vknqtdvq9
+        // Based on a logistic curve, which caps out at MaxDamage
+        var heatK = 0.005;
+        var a = 1;
+        var y = temperature.DamageCap;
+        var c = y * 2;
 
-                var diff = Math.Abs(temperature.CurrentTemperature - heatDamageThreshold);
-                var tempDamage = c / (1 + a * Math.Pow(Math.E, -heatK * diff)) - y;
-                _damageableSystem.TryChangeDamage(uid, temperature.HeatDamage * tempDamage, ignoreResistances: true, interruptsDoAfters: false);
-            }
-            else if (temperature.CurrentTemperature <= coldDamageThreshold)
-            {
-                if (!temperature.TakingDamage)
-                {
-                    _adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} started taking low temperature damage");
-                    temperature.TakingDamage = true;
-                }
+        var heatDamageThreshold = temperature.ParentHeatDamageThreshold ?? temperature.HeatDamageThreshold;
+        var coldDamageThreshold = temperature.ParentColdDamageThreshold ?? temperature.ColdDamageThreshold;
 
-                var diff = Math.Abs(temperature.CurrentTemperature - coldDamageThreshold);
-                var tempDamage =
-                    Math.Sqrt(diff * (Math.Pow(temperature.DamageCap.Double(), 2) / coldDamageThreshold));
-                _damageableSystem.TryChangeDamage(uid, temperature.ColdDamage * tempDamage, ignoreResistances: true, interruptsDoAfters: false);
-            }
-            else if (temperature.TakingDamage)
+        if (temperature.CurrentTemperature >= heatDamageThreshold)
+        {
+            if (!temperature.TakingDamage)
             {
-                _adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} stopped taking temperature damage");
-                temperature.TakingDamage = false;
+                _adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} started taking high temperature damage");
+                temperature.TakingDamage = true;
             }
-        }
 
-        private void OnTemperatureChangeAttempt(EntityUid uid, TemperatureProtectionComponent component,
-            InventoryRelayedEvent<ModifyChangedTemperatureEvent> args)
-        {
-            args.Args.TemperatureDelta *= component.Coefficient;
+            var diff = Math.Abs(temperature.CurrentTemperature - heatDamageThreshold);
+            var tempDamage = c / (1 + a * Math.Pow(Math.E, -heatK * diff)) - y;
+            _damageable.TryChangeDamage(uid, temperature.HeatDamage * tempDamage, ignoreResistances: true, interruptsDoAfters: false);
         }
-
-        private void OnParentChange(EntityUid uid, TemperatureComponent component,
-            ref EntParentChangedMessage args)
+        else if (temperature.CurrentTemperature <= coldDamageThreshold)
         {
-            var temperatureQuery = GetEntityQuery<TemperatureComponent>();
-            var transformQuery = GetEntityQuery<TransformComponent>();
-            var thresholdsQuery = GetEntityQuery<ContainerTemperatureDamageThresholdsComponent>();
-            // We only need to update thresholds if the thresholds changed for the entity's ancestors.
-            var oldThresholds = args.OldParent != null
-                ? RecalculateParentThresholds(args.OldParent.Value, transformQuery, thresholdsQuery)
-                : (null, null);
-            var newThresholds = RecalculateParentThresholds(transformQuery.GetComponent(uid).ParentUid, transformQuery, thresholdsQuery);
-
-            if (oldThresholds != newThresholds)
+            if (!temperature.TakingDamage)
             {
-                RecursiveThresholdUpdate(uid, temperatureQuery, transformQuery, thresholdsQuery);
+                _adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} started taking low temperature damage");
+                temperature.TakingDamage = true;
             }
-        }
 
-        private void OnParentThresholdStartup(EntityUid uid, ContainerTemperatureDamageThresholdsComponent component,
-            ComponentStartup args)
+            var diff = Math.Abs(temperature.CurrentTemperature - coldDamageThreshold);
+            var tempDamage =
+                Math.Sqrt(diff * (Math.Pow(temperature.DamageCap.Double(), 2) / coldDamageThreshold));
+            _damageable.TryChangeDamage(uid, temperature.ColdDamage * tempDamage, ignoreResistances: true, interruptsDoAfters: false);
+        }
+        else if (temperature.TakingDamage)
         {
-            RecursiveThresholdUpdate(uid, GetEntityQuery<TemperatureComponent>(), GetEntityQuery<TransformComponent>(),
-                GetEntityQuery<ContainerTemperatureDamageThresholdsComponent>());
+            _adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} stopped taking temperature damage");
+            temperature.TakingDamage = false;
         }
+    }
+
+    private void OnTemperatureChangeAttempt(EntityUid uid, TemperatureProtectionComponent component,
+        InventoryRelayedEvent<ModifyChangedTemperatureEvent> args)
+    {
+        args.Args.TemperatureDelta *= component.Coefficient;
+    }
 
-        private void OnParentThresholdShutdown(EntityUid uid, ContainerTemperatureDamageThresholdsComponent component,
-            ComponentShutdown args)
+    private void OnParentChange(EntityUid uid, TemperatureComponent component,
+        ref EntParentChangedMessage args)
+    {
+        var temperatureQuery = GetEntityQuery<TemperatureComponent>();
+        var transformQuery = GetEntityQuery<TransformComponent>();
+        var thresholdsQuery = GetEntityQuery<ContainerTemperatureDamageThresholdsComponent>();
+        // We only need to update thresholds if the thresholds changed for the entity's ancestors.
+        var oldThresholds = args.OldParent != null
+            ? RecalculateParentThresholds(args.OldParent.Value, transformQuery, thresholdsQuery)
+            : (null, null);
+        var newThresholds = RecalculateParentThresholds(transformQuery.GetComponent(uid).ParentUid, transformQuery, thresholdsQuery);
+
+        if (oldThresholds != newThresholds)
         {
-            RecursiveThresholdUpdate(uid, GetEntityQuery<TemperatureComponent>(), GetEntityQuery<TransformComponent>(),
-                GetEntityQuery<ContainerTemperatureDamageThresholdsComponent>());
+            RecursiveThresholdUpdate(uid, temperatureQuery, transformQuery, thresholdsQuery);
         }
+    }
 
-        /// <summary>
-        /// Recalculate and apply parent thresholds for the root entity and all its descendant.
-        /// </summary>
-        /// <param name="root"></param>
-        /// <param name="temperatureQuery"></param>
-        /// <param name="transformQuery"></param>
-        /// <param name="tempThresholdsQuery"></param>
-        private void RecursiveThresholdUpdate(EntityUid root, EntityQuery<TemperatureComponent> temperatureQuery,
-            EntityQuery<TransformComponent> transformQuery,
-            EntityQuery<ContainerTemperatureDamageThresholdsComponent> tempThresholdsQuery)
-        {
-            RecalculateAndApplyParentThresholds(root, temperatureQuery, transformQuery, tempThresholdsQuery);
+    private void OnParentThresholdStartup(EntityUid uid, ContainerTemperatureDamageThresholdsComponent component,
+        ComponentStartup args)
+    {
+        RecursiveThresholdUpdate(uid, GetEntityQuery<TemperatureComponent>(), GetEntityQuery<TransformComponent>(),
+            GetEntityQuery<ContainerTemperatureDamageThresholdsComponent>());
+    }
 
-            foreach (var child in Transform(root).ChildEntities)
-            {
-                RecursiveThresholdUpdate(child, temperatureQuery, transformQuery, tempThresholdsQuery);
-            }
-        }
+    private void OnParentThresholdShutdown(EntityUid uid, ContainerTemperatureDamageThresholdsComponent component,
+        ComponentShutdown args)
+    {
+        RecursiveThresholdUpdate(uid, GetEntityQuery<TemperatureComponent>(), GetEntityQuery<TransformComponent>(),
+            GetEntityQuery<ContainerTemperatureDamageThresholdsComponent>());
+    }
+
+    /// <summary>
+    /// Recalculate and apply parent thresholds for the root entity and all its descendant.
+    /// </summary>
+    /// <param name="root"></param>
+    /// <param name="temperatureQuery"></param>
+    /// <param name="transformQuery"></param>
+    /// <param name="tempThresholdsQuery"></param>
+    private void RecursiveThresholdUpdate(EntityUid root, EntityQuery<TemperatureComponent> temperatureQuery,
+        EntityQuery<TransformComponent> transformQuery,
+        EntityQuery<ContainerTemperatureDamageThresholdsComponent> tempThresholdsQuery)
+    {
+        RecalculateAndApplyParentThresholds(root, temperatureQuery, transformQuery, tempThresholdsQuery);
 
-        /// <summary>
-        /// Recalculate parent thresholds and apply them on the uid temperature component.
-        /// </summary>
-        /// <param name="uid"></param>
-        /// <param name="temperatureQuery"></param>
-        /// <param name="transformQuery"></param>
-        /// <param name="tempThresholdsQuery"></param>
-        private void RecalculateAndApplyParentThresholds(EntityUid uid,
-            EntityQuery<TemperatureComponent> temperatureQuery, EntityQuery<TransformComponent> transformQuery,
-            EntityQuery<ContainerTemperatureDamageThresholdsComponent> tempThresholdsQuery)
+        foreach (var child in Transform(root).ChildEntities)
         {
-            if (!temperatureQuery.TryGetComponent(uid, out var temperature))
-            {
-                return;
-            }
+            RecursiveThresholdUpdate(child, temperatureQuery, transformQuery, tempThresholdsQuery);
+        }
+    }
 
-            var newThresholds = RecalculateParentThresholds(transformQuery.GetComponent(uid).ParentUid, transformQuery, tempThresholdsQuery);
-            temperature.ParentHeatDamageThreshold = newThresholds.Item1;
-            temperature.ParentColdDamageThreshold = newThresholds.Item2;
+    /// <summary>
+    /// Recalculate parent thresholds and apply them on the uid temperature component.
+    /// </summary>
+    /// <param name="uid"></param>
+    /// <param name="temperatureQuery"></param>
+    /// <param name="transformQuery"></param>
+    /// <param name="tempThresholdsQuery"></param>
+    private void RecalculateAndApplyParentThresholds(EntityUid uid,
+        EntityQuery<TemperatureComponent> temperatureQuery, EntityQuery<TransformComponent> transformQuery,
+        EntityQuery<ContainerTemperatureDamageThresholdsComponent> tempThresholdsQuery)
+    {
+        if (!temperatureQuery.TryGetComponent(uid, out var temperature))
+        {
+            return;
         }
 
-        /// <summary>
-        /// Recalculate Parent Heat/Cold DamageThreshold by recursively checking each ancestor and fetching the
-        /// maximum HeatDamageThreshold and the minimum ColdDamageThreshold if any exists (aka the best value for each).
-        /// </summary>
-        /// <param name="initialParentUid"></param>
-        /// <param name="transformQuery"></param>
-        /// <param name="tempThresholdsQuery"></param>
-        private (float?, float?) RecalculateParentThresholds(
-            EntityUid initialParentUid,
-            EntityQuery<TransformComponent> transformQuery,
-            EntityQuery<ContainerTemperatureDamageThresholdsComponent> tempThresholdsQuery)
+        var newThresholds = RecalculateParentThresholds(transformQuery.GetComponent(uid).ParentUid, transformQuery, tempThresholdsQuery);
+        temperature.ParentHeatDamageThreshold = newThresholds.Item1;
+        temperature.ParentColdDamageThreshold = newThresholds.Item2;
+    }
+
+    /// <summary>
+    /// Recalculate Parent Heat/Cold DamageThreshold by recursively checking each ancestor and fetching the
+    /// maximum HeatDamageThreshold and the minimum ColdDamageThreshold if any exists (aka the best value for each).
+    /// </summary>
+    /// <param name="initialParentUid"></param>
+    /// <param name="transformQuery"></param>
+    /// <param name="tempThresholdsQuery"></param>
+    private (float?, float?) RecalculateParentThresholds(
+        EntityUid initialParentUid,
+        EntityQuery<TransformComponent> transformQuery,
+        EntityQuery<ContainerTemperatureDamageThresholdsComponent> tempThresholdsQuery)
+    {
+        // Recursively check parents for the best threshold available
+        var parentUid = initialParentUid;
+        float? newHeatThreshold = null;
+        float? newColdThreshold = null;
+        while (parentUid.IsValid())
         {
-            // Recursively check parents for the best threshold available
-            var parentUid = initialParentUid;
-            float? newHeatThreshold = null;
-            float? newColdThreshold = null;
-            while (parentUid.IsValid())
+            if (tempThresholdsQuery.TryGetComponent(parentUid, out var newThresholds))
             {
-                if (tempThresholdsQuery.TryGetComponent(parentUid, out var newThresholds))
+                if (newThresholds.HeatDamageThreshold != null)
                 {
-                    if (newThresholds.HeatDamageThreshold != null)
-                    {
-                        newHeatThreshold = Math.Max(newThresholds.HeatDamageThreshold.Value,
-                            newHeatThreshold ?? 0);
-                    }
-
-                    if (newThresholds.ColdDamageThreshold != null)
-                    {
-                        newColdThreshold = Math.Min(newThresholds.ColdDamageThreshold.Value,
-                            newColdThreshold ?? float.MaxValue);
-                    }
+                    newHeatThreshold = Math.Max(newThresholds.HeatDamageThreshold.Value,
+                        newHeatThreshold ?? 0);
                 }
 
-                parentUid = transformQuery.GetComponent(parentUid).ParentUid;
+                if (newThresholds.ColdDamageThreshold != null)
+                {
+                    newColdThreshold = Math.Min(newThresholds.ColdDamageThreshold.Value,
+                        newColdThreshold ?? float.MaxValue);
+                }
             }
 
-            return (newHeatThreshold, newColdThreshold);
+            parentUid = transformQuery.GetComponent(parentUid).ParentUid;
         }
+
+        return (newHeatThreshold, newColdThreshold);
     }
+}
 
-    public sealed class OnTemperatureChangeEvent : EntityEventArgs
-    {
-        public float CurrentTemperature { get; }
-        public float LastTemperature { get; }
-        public float TemperatureDelta { get; }
+public sealed class OnTemperatureChangeEvent : EntityEventArgs
+{
+    public float CurrentTemperature { get; }
+    public float LastTemperature { get; }
+    public float TemperatureDelta { get; }
 
-        public OnTemperatureChangeEvent(float current, float last, float delta)
-        {
-            CurrentTemperature = current;
-            LastTemperature = last;
-            TemperatureDelta = delta;
-        }
+    public OnTemperatureChangeEvent(float current, float last, float delta)
+    {
+        CurrentTemperature = current;
+        LastTemperature = last;
+        TemperatureDelta = delta;
     }
 }