From ffc9a24ea0724d756cfa7ca5c0c16c9286d418e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= <6766154+Zumorica@users.noreply.github.com> Date: Fri, 7 Aug 2020 16:23:16 +0200 Subject: [PATCH] Adds barotrauma (pressure damage) (#1605) * Adds barotrauma, disables it for now * At least show status effect, but don't damage the mobs * Fix switch misuse --- Content.Server/Atmos/GasMixture.cs | 2 +- .../Atmos/Reactions/GasReactionPrototype.cs | 2 +- .../Components/Atmos/BarotraumaComponent.cs | 98 ++++++++++++++++++ .../Atmos/PressureProtectionComponent.cs | 27 +++++ .../Components/GUI/InventoryComponent.cs | 49 ++++++++- .../EntitySystems/BarotraumaSystem.cs | 29 ++++++ .../GameObjects/IPressureProtection.cs | 8 ++ Content.Shared/Atmos/Atmospherics.cs | 38 +++++++ .../Mobs/SharedStatusEffectsComponent.cs | 1 + .../Entities/Mobs/Species/human.yml | 1 + .../StatusEffects/Pressure/highpressure1.png | Bin 0 -> 591 bytes .../StatusEffects/Pressure/highpressure2.png | Bin 0 -> 578 bytes .../StatusEffects/Pressure/lowpressure1.png | Bin 0 -> 601 bytes .../StatusEffects/Pressure/lowpressure2.png | Bin 0 -> 506 bytes .../StatusEffects/Pressure/meta.json | 47 +++++++++ SpaceStation14.sln.DotSettings | 1 + 16 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs create mode 100644 Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs create mode 100644 Content.Server/GameObjects/EntitySystems/BarotraumaSystem.cs create mode 100644 Content.Server/Interfaces/GameObjects/IPressureProtection.cs create mode 100644 Resources/Textures/Interface/StatusEffects/Pressure/highpressure1.png create mode 100644 Resources/Textures/Interface/StatusEffects/Pressure/highpressure2.png create mode 100644 Resources/Textures/Interface/StatusEffects/Pressure/lowpressure1.png create mode 100644 Resources/Textures/Interface/StatusEffects/Pressure/lowpressure2.png create mode 100644 Resources/Textures/Interface/StatusEffects/Pressure/meta.json 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 0000000000000000000000000000000000000000..daebd742be0abda30eb116df931d2857f89b9cea GIT binary patch literal 591 zcmV-V03SN=sAP_r6?EDLoLIlf5z$TTI&4G4T2of7j zX`|`(KuL}}yebySoIBsMxeIw=Np>?c?=v6oOcu7R$oTY-#YWuT>3%xEA&cVPM(jzy z=@2(v6&msX?1J#qHBEaw!Ib>~Hm8W&tNYy8=p!`=aK z0K5bsd6Y1J7Q=B99)AvP);|J5=U_B0&8x)0b=;L~(EwMMb>J|NVHfusFp#5^*YyA(VH0wSnf1qB1B zjhk{_)!Ydn3`~uloI*MnYR`*aw=#q^hUs8PIvQ)nQqSux=}JfA;2qEl5UQe+UtXMj zuM81%7Kl&NsK9!29|Z7V=ecA~z2$^lN6r)+pT7cf$-L;~QW?`?RH0lW3DS+h=OK|m;lnj^r0ILSp$#{so07b96QHY=^ zP$5E;4u;O?Rsv|mGDJ|h)%I*#d_vwA6VnM;j-u_bD%ThHS9&o~?_HbAwf!O4#Hv@d d^_SDF>mOg4)}B91JL>=d002ovPDHLkV1n~65+48n literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/highpressure2.png b/Resources/Textures/Interface/StatusEffects/Pressure/highpressure2.png new file mode 100644 index 0000000000000000000000000000000000000000..85f74289aaa222102c91954f6cc10faf76aa18ee GIT binary patch literal 578 zcmV-I0=@l-P)1u5NR_CrClCu#bGKGWJ2iiSAHZ;Hqz-Jb^A{MASW%^0_yLTt-GGFe>Efyb z3zr?#N_XNG%+L$Cj-A+PtG-gy#QyB}>F3Xh3~)= zAGqwp%df7}HfNyJ?YH&%|9rJF_6N_e0XY7B<81B)phDQ>YYrYu5PW}BY3rSwZ0srd z^uhY(^$r0dU_Kmjbzg|8R?8(z^%*FN!nze(0jLng7Vm+r08|Kv{o18iZ3^ zcl56o{FEXE|1YUrYMZHFkJDpKCoboMiT+&oa@pC(XqN>Sr{?y9A5IUhzuV^2I9u(q Q?f?J)07*qoM6N<$f*P?BdjJ3c literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure1.png b/Resources/Textures/Interface/StatusEffects/Pressure/lowpressure1.png new file mode 100644 index 0000000000000000000000000000000000000000..27153cc54276cf663a52c5c07dc5926eb1aa1766 GIT binary patch literal 601 zcmV-f0;c_mP)r+j!nOFKccEkOp~;Mo|QRGSI%e{h&02aT5BI0sQHay*BTr z9)Eg7-T|db4MASxZf~5tOK7(@CP#vF7RX;yRH}?U89+4$?^+?Nh%^MMxf=2$uK>yx zp+bPHxpuZ^qT=?(8kE})ssm)rvoc0R0rRI_tsEVIAPJU4hW|IT%^iR;38SlJLlxFI zMTG!vKUgUQX&GiADDo$R!tj#;IOiz{Qn`QIvuW~46<$p8PC#`jnhqsclZDC?!5~KIm?KR)(A3jyNUWm0cr&1otcThf8<9X)^s+I zQZCF9LTEuL14t=x9EYusO#n9J6-Mwv!MNq(aFnxebdgeOL9FPQZ(nX=JjCY+7lOw< z9LG_rR4C;N?4FsJ`1l2r&*Bh@RiFx-0}!ysO6vz&1vq|E22iR1!1wbT0R59;?04g! z3&4i=rEIPRFb(mabj?BI2#oi20BqZy#DbkwhVA}e(*1bCPE!UDLhw3nL>Nrs^M^5P z_v!U|T2r800U<=b_rNlnt4ON}vyfH=rsbEKk(k+OqzB-an%Lz!o@@QP*e=&+0}JxC z08}+?=$D$<6;BI7s|Wm26RYCsEJ+U_Jd(7fbOh7p^W}|e##8~4%pux{o@+&*lBQ!J zK$3Y}JT#vHOPG#KE~0RJJ=bE;zD~?t2oP?NcK0g-n4LzZ5K2>Eb{Y&AmDW<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>