diff --git a/Content.Server/Atmos/Components/FlammableComponent.cs b/Content.Server/Atmos/Components/FlammableComponent.cs index ed54aa538d..88be46c850 100644 --- a/Content.Server/Atmos/Components/FlammableComponent.cs +++ b/Content.Server/Atmos/Components/FlammableComponent.cs @@ -31,5 +31,9 @@ namespace Content.Server.Atmos.Components [ViewVariables(VVAccess.ReadWrite)] [DataField("canResistFire")] public bool CanResistFire { get; private set; } = false; + + [DataField("damage", required: true)] + [ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier Damage = default!; } } diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index f39a0f6a03..e3a3174574 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Content.Server.Alert; using Content.Server.Atmos.Components; using Content.Server.Stunnable; @@ -25,16 +26,23 @@ namespace Content.Server.Atmos.EntitySystems [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly StunSystem _stunSystem = default!; [Dependency] private readonly TemperatureSystem _temperatureSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; private const float MinimumFireStacks = -10f; private const float MaximumFireStacks = 20f; private const float UpdateTime = 1f; + private const float MinIgnitionTemperature = 373.15f; + private float _timer = 0f; + private Dictionary _fireEvents = new(); + // TODO: Port the rest of Flammable. public override void Initialize() { + UpdatesAfter.Add(typeof(AtmosphereSystem)); + SubscribeLocalEvent(OnInteractUsingEvent); SubscribeLocalEvent(OnCollideEvent); SubscribeLocalEvent(OnIsHotEvent); @@ -94,8 +102,13 @@ namespace Content.Server.Atmos.EntitySystems private void OnTileFireEvent(EntityUid uid, FlammableComponent flammable, TileFireEvent args) { - AdjustFireStacks(uid, 3, flammable); - Ignite(uid, flammable); + var tempDelta = args.Temperature - MinIgnitionTemperature; + + var maxTemp = 0f; + _fireEvents.TryGetValue(flammable, out maxTemp); + + if (tempDelta > maxTemp) + _fireEvents[flammable] = tempDelta; } public void UpdateAppearance(EntityUid uid, FlammableComponent? flammable = null, AppearanceComponent? appearance = null) @@ -168,13 +181,27 @@ namespace Content.Server.Atmos.EntitySystems flammable.Owner.SpawnTimer(2000, () => { flammable.Resisting = false; - flammable.FireStacks -= 3f; + flammable.FireStacks -= 1f; UpdateAppearance(uid, flammable); }); } public override void Update(float frameTime) { + // process all fire events + foreach (var (flammable, deltaTemp) in _fireEvents) + { + // 100 -> 1, 200 -> 2, 400 -> 3... + var fireStackMod = Math.Max(MathF.Log2(deltaTemp / 100) + 1, 0); + var fireStackDelta = fireStackMod - flammable.FireStacks; + if (fireStackDelta > 0) + { + AdjustFireStacks(flammable.OwnerUid, fireStackDelta, flammable); + } + Ignite(flammable.OwnerUid, flammable); + } + _fireEvents.Clear(); + _timer += frameTime; if (_timer < UpdateTime) @@ -205,7 +232,11 @@ namespace Content.Server.Atmos.EntitySystems if (flammable.FireStacks > 0) { - _temperatureSystem.ChangeHeat(uid, 80000 * flammable.FireStacks); + // TODO FLAMMABLE: further balancing + var damageScale = Math.Min((int)flammable.FireStacks, 5); + _temperatureSystem.ChangeHeat(uid, 12500 * damageScale); + _damageableSystem.TryChangeDamage(uid, flammable.Damage * damageScale); + AdjustFireStacks(uid, -0.1f * (flammable.Resisting ? 10f : 1f), flammable); } else diff --git a/Content.Server/Body/Components/RespiratorComponent.cs b/Content.Server/Body/Components/RespiratorComponent.cs index 988fa431af..0c809b9560 100644 --- a/Content.Server/Body/Components/RespiratorComponent.cs +++ b/Content.Server/Body/Components/RespiratorComponent.cs @@ -30,9 +30,6 @@ namespace Content.Server.Body.Components private float _accumulatedFrameTime; - private bool _isShivering; - private bool _isSweating; - [ViewVariables] [DataField("needsGases")] public Dictionary NeedsGases { get; set; } = new(); [ViewVariables] [DataField("producesGases")] public Dictionary ProducesGases { get; set; } = new(); @@ -253,52 +250,28 @@ namespace Content.Server.Body.Components { totalMetabolismTempChange += Math.Min(targetHeat, ImplicitHeatRegulation); } + + temperatureSystem.ChangeHeat(Owner.Uid, totalMetabolismTempChange, true, temperatureComponent); + // recalc difference and target heat tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - NormalBodyTemperature); targetHeat = tempDiff * temperatureComponent.HeatCapacity; - temperatureSystem.ChangeHeat(Owner.Uid, totalMetabolismTempChange, true, temperatureComponent); - // if body temperature is not within comfortable, thermal regulation // processes starts - if (tempDiff < ThermalRegulationTemperatureThreshold) - { - if (_isShivering || _isSweating) - { - Owner.PopupMessage(Loc.GetString("metabolism-component-is-comfortable")); - } - - _isShivering = false; - _isSweating = false; + if (tempDiff > ThermalRegulationTemperatureThreshold) return; - } var actionBlocker = EntitySystem.Get(); if (temperatureComponent.CurrentTemperature > NormalBodyTemperature) { if (!actionBlocker.CanSweat(OwnerUid)) return; - if (!_isSweating) - { - Owner.PopupMessage(Loc.GetString("metabolism-component-is-sweating")); - _isSweating = true; - } - - // creadth: sweating does not help in airless environment - if (EntitySystem.Get().GetTileMixture(Owner.Transform.Coordinates) is not {}) - { - temperatureSystem.ChangeHeat(OwnerUid, -Math.Min(targetHeat, SweatHeatRegulation), true, temperatureComponent); - } + temperatureSystem.ChangeHeat(OwnerUid, -Math.Min(targetHeat, SweatHeatRegulation), true, temperatureComponent); } else { if (!actionBlocker.CanShiver(OwnerUid)) return; - if (!_isShivering) - { - Owner.PopupMessage(Loc.GetString("metabolism-component-is-shivering")); - _isShivering = true; - } - temperatureSystem.ChangeHeat(OwnerUid, Math.Min(targetHeat, ShiveringHeatRegulation), true, temperatureComponent); } } diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml index 75def55f9c..d4c974565a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml @@ -63,6 +63,9 @@ - type: Flammable fireSpread: true canResistFire: true + damage: + types: + Heat: 1 #per second, scales with number of fire 'stacks' - type: Temperature heatDamageThreshold: 360 coldDamageThreshold: 260 diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 0acf65a678..3935910caf 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -173,6 +173,9 @@ - type: Flammable fireSpread: true canResistFire: true + damage: + types: + Heat: 1 #per second, scales with number of fire 'stacks' - type: Temperature heatDamageThreshold: 360 coldDamageThreshold: 260