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>