Merge branch 'master' into 2020-08-19-firelocks

This commit is contained in:
Víctor Aguilera Puerto
2020-09-09 22:12:38 +02:00
committed by GitHub
21 changed files with 488 additions and 154 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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)
{

View File

@@ -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<IRobustRandom>();
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.

View File

@@ -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);
}

View File

@@ -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;
}
}
}