diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs
index f7efa6e99d..cad0a27730 100644
--- a/Content.Server/Atmos/GasMixture.cs
+++ b/Content.Server/Atmos/GasMixture.cs
@@ -462,7 +462,7 @@ namespace Content.Server.Atmos
continue;
reaction = prototype.React(this, holder);
- if(reaction.HasFlag(ReactionResult.NoReaction))
+ if(reaction.HasFlag(ReactionResult.StopReactions))
break;
}
}
diff --git a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs
index 6f1023750e..d8e42bab39 100644
--- a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs
+++ b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs
@@ -13,7 +13,7 @@ namespace Content.Server.Atmos.Reactions
{
NoReaction = 0,
Reacting = 1,
-
+ StopReactions = 2,
}
[Prototype("gasReaction")]
diff --git a/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs b/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
new file mode 100644
index 0000000000..8268bf382e
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
@@ -0,0 +1,98 @@
+using System.Runtime.CompilerServices;
+using CannyFastMath;
+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.Mobs;
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameObjects.Systems;
+
+namespace Content.Server.GameObjects.Components.Atmos
+{
+ ///
+ /// Barotrauma: injury because of changes in air pressure.
+ ///
+ [RegisterComponent]
+ public class BarotraumaComponent : Component
+ {
+ public override string Name => "Barotrauma";
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Update(float frameTime)
+ {
+ if (!Owner.TryGetComponent(out DamageableComponent damageable)) return;
+ Owner.TryGetComponent(out ServerStatusEffectsComponent status);
+
+ var coordinates = Owner.Transform.GridPosition;
+ var gridAtmos = EntitySystem.Get().GetGridAtmosphere(coordinates.GridID);
+ var tile = gridAtmos?.GetTile(coordinates);
+
+ var pressure = 1f;
+ var highPressureMultiplier = 1f;
+ var lowPressureMultiplier = 1f;
+
+ foreach (var protection in Owner.GetAllComponents())
+ {
+ highPressureMultiplier *= protection.HighPressureMultiplier;
+ lowPressureMultiplier *= protection.LowPressureMultiplier;
+ }
+
+ if (tile?.Air != null)
+ pressure = MathF.Max(tile.Air.Pressure, 1f);
+
+ switch (pressure)
+ {
+ // Low pressure.
+ case var p when p <= Atmospherics.WarningLowPressure:
+ pressure *= lowPressureMultiplier;
+
+ if(pressure > Atmospherics.WarningLowPressure)
+ goto default;
+
+ // TODO ATMOS Uncomment this when saltern is pressurized
+ //damageable.TakeDamage(DamageType.Brute, Atmospherics.LowPressureDamage, Owner, null);
+
+ if (status == null) break;
+
+ if (pressure <= Atmospherics.HazardLowPressure)
+ {
+ status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure2.png", null);
+ break;
+ }
+
+ status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure1.png", null);
+ break;
+
+ // High pressure.
+ case var p when p >= Atmospherics.WarningHighPressure:
+ pressure *= highPressureMultiplier;
+
+ if(pressure < Atmospherics.WarningHighPressure)
+ goto default;
+
+ var damage = (int) MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage);
+
+ // TODO ATMOS Uncomment this when saltern is pressurized
+ //damageable.TakeDamage(DamageType.Brute, damage, Owner, null);
+
+ if (status == null) break;
+
+ if (pressure >= Atmospherics.HazardHighPressure)
+ {
+ status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure2.png", null);
+ break;
+ }
+
+ status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure1.png", null);
+ break;
+
+ // Normal pressure.
+ default:
+ status?.RemoveStatusEffect(StatusEffect.Pressure);
+ break;
+ }
+
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs b/Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs
new file mode 100644
index 0000000000..6c4ea57a38
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs
@@ -0,0 +1,27 @@
+using Content.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.GameObjects.Components.Atmos
+{
+ [RegisterComponent]
+ public class PressureProtectionComponent : Component, IPressureProtection
+ {
+ public override string Name => "PressureProtection";
+
+ [ViewVariables]
+ public float HighPressureMultiplier { get; private set; }
+
+ [ViewVariables]
+ public float LowPressureMultiplier { get; private set; }
+
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+
+ serializer.DataField(this, x => HighPressureMultiplier, "highPressureMultiplier", 1f);
+ serializer.DataField(this, x => LowPressureMultiplier, "lowPressureMultiplier", 1f);
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs
index 1c09c3bcf2..5a9ed13f6a 100644
--- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs
+++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs
@@ -8,6 +8,7 @@ using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.EntitySystems.Click;
using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Server.Interfaces;
+using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.EntitySystems;
using Robust.Server.GameObjects.Components.Container;
@@ -26,7 +27,7 @@ using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventory
namespace Content.Server.GameObjects
{
[RegisterComponent]
- public class InventoryComponent : SharedInventoryComponent, IExAct, IEffectBlocker
+ public class InventoryComponent : SharedInventoryComponent, IExAct, IEffectBlocker, IPressureProtection
{
#pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
@@ -51,6 +52,52 @@ namespace Content.Server.GameObjects
}
}
+ // Optimization: Cache this
+ [ViewVariables]
+ public float HighPressureMultiplier
+ {
+ get
+ {
+ var multiplier = 1f;
+
+ foreach (var (slot, containerSlot) in SlotContainers)
+ {
+ foreach (var entity in containerSlot.ContainedEntities)
+ {
+ foreach (var protection in entity.GetAllComponents())
+ {
+ multiplier *= protection.HighPressureMultiplier;
+ }
+ }
+ }
+
+ return multiplier;
+ }
+ }
+
+ // Optimization: Cache this
+ [ViewVariables]
+ public float LowPressureMultiplier
+ {
+ get
+ {
+ var multiplier = 1f;
+
+ foreach (var (slot, containerSlot) in SlotContainers)
+ {
+ foreach (var entity in containerSlot.ContainedEntities)
+ {
+ foreach (var protection in entity.GetAllComponents())
+ {
+ multiplier *= protection.LowPressureMultiplier;
+ }
+ }
+ }
+
+ return multiplier;
+ }
+ }
+
bool IEffectBlocker.CanSlip()
{
if(Owner.TryGetComponent(out InventoryComponent inventoryComponent) &&
diff --git a/Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs b/Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs
new file mode 100644
index 0000000000..2210afb488
--- /dev/null
+++ b/Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs
@@ -0,0 +1,29 @@
+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 = 0.5f;
+
+ 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/Interfaces/GameObjects/IPressureProtection.cs b/Content.Server/Interfaces/GameObjects/IPressureProtection.cs
new file mode 100644
index 0000000000..ed18e8f1d1
--- /dev/null
+++ b/Content.Server/Interfaces/GameObjects/IPressureProtection.cs
@@ -0,0 +1,8 @@
+namespace Content.Server.Interfaces.GameObjects
+{
+ public interface IPressureProtection
+ {
+ public float HighPressureMultiplier { get; }
+ public float LowPressureMultiplier { get; }
+ }
+}
diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs
index 74d1db086e..5cdd96327b 100644
--- a/Content.Shared/Atmos/Atmospherics.cs
+++ b/Content.Shared/Atmos/Atmospherics.cs
@@ -158,6 +158,44 @@ namespace Content.Shared.Atmos
public const float PhoronUpperTemperature = (1370f+T0C);
public const float PhoronOxygenFullburn = 10f;
public const float PhoronBurnRateDelta = 9f;
+
+ ///
+ /// Determines at what pressure the ultra-high pressure red icon is displayed.
+ ///
+ public const float HazardHighPressure = 550f;
+
+ ///
+ /// Determines when the orange pressure icon is displayed.
+ ///
+ public const float WarningHighPressure = 0.7f * HazardHighPressure;
+
+ ///
+ /// Determines when the gray low pressure icon is displayed.
+ ///
+ public const float WarningLowPressure = 2.5f * HazardLowPressure;
+
+ ///
+ /// Determines when the black ultra-low pressure icon is displayed.
+ ///
+ public const float HazardLowPressure = 20f;
+
+ ///
+ /// The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT,
+ /// with the maximum of MaxHighPressureDamage.
+ ///
+ public const float PressureDamageCoefficient = 4;
+
+ ///
+ /// Maximum amount of damage that can be endured with high pressure.
+ ///
+ public const int MaxHighPressureDamage = 4;
+
+ ///
+ /// The amount of damage someone takes when in a low pressure area
+ /// (The pressure threshold is so low that it doesn't make sense to do any calculations,
+ /// so it just applies this flat value).
+ ///
+ public const int LowPressureDamage = 4;
}
///
diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs
index d7fcefb95a..189476b442 100644
--- a/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs
+++ b/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs
@@ -56,6 +56,7 @@ namespace Content.Shared.GameObjects.Components.Mobs
Health,
Hunger,
Thirst,
+ Pressure,
Stun,
Buckled,
Piloting,
diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml
index 4c65dc043d..a143640d1c 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/human.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml
@@ -12,6 +12,7 @@
- type: Hands
- type: MovementSpeedModifier
- type: MovedByPressure
+ - type: Barotrauma
- type: DamageOnHighSpeedImpact
soundHit: /Audio/Effects/hit_kick.ogg
- type: Hunger
diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/highpressure1.png b/Resources/Textures/Interface/StatusEffects/Pressure/highpressure1.png
new file mode 100644
index 0000000000..daebd742be
Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Pressure/highpressure1.png differ
diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/highpressure2.png b/Resources/Textures/Interface/StatusEffects/Pressure/highpressure2.png
new file mode 100644
index 0000000000..85f74289aa
Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Pressure/highpressure2.png differ
diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure1.png b/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure1.png
new file mode 100644
index 0000000000..27153cc542
Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure1.png differ
diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure2.png b/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure2.png
new file mode 100644
index 0000000000..d94b77ea1a
Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure2.png differ
diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/meta.json b/Resources/Textures/Interface/StatusEffects/Pressure/meta.json
new file mode 100644
index 0000000000..493417f7bf
--- /dev/null
+++ b/Resources/Textures/Interface/StatusEffects/Pressure/meta.json
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "CC-BY-SA 3.0",
+ "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd",
+ "states": [
+ {
+ "name": "highpressure1",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "highpressure2",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "lowpressure1",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "lowpressure2",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 0d0c37af86..bd8ed2aff7 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -45,6 +45,7 @@
<data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
True
True
+ True
True
<data />
<data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>