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
This commit is contained in:
Víctor Aguilera Puerto
2020-08-07 16:23:16 +02:00
committed by GitHub
parent 079937a9fe
commit ffc9a24ea0
16 changed files with 300 additions and 3 deletions

View File

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

View File

@@ -13,7 +13,7 @@ namespace Content.Server.Atmos.Reactions
{
NoReaction = 0,
Reacting = 1,
StopReactions = 2,
}
[Prototype("gasReaction")]

View File

@@ -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
{
/// <summary>
/// Barotrauma: injury because of changes in air pressure.
/// </summary>
[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<AtmosphereSystem>().GetGridAtmosphere(coordinates.GridID);
var tile = gridAtmos?.GetTile(coordinates);
var pressure = 1f;
var highPressureMultiplier = 1f;
var lowPressureMultiplier = 1f;
foreach (var protection in Owner.GetAllComponents<IPressureProtection>())
{
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;
}
}
}
}

View File

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

View File

@@ -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<IPressureProtection>())
{
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<IPressureProtection>())
{
multiplier *= protection.LowPressureMultiplier;
}
}
}
return multiplier;
}
}
bool IEffectBlocker.CanSlip()
{
if(Owner.TryGetComponent(out InventoryComponent inventoryComponent) &&

View File

@@ -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;
/// <inheritdoc />
public override void Update(float frameTime)
{
_timer += frameTime;
if (_timer < TimePerUpdate) return;
_timer = 0f;
foreach (var barotraumaComp in ComponentManager.EntityQuery<BarotraumaComponent>())
{
barotraumaComp.Update(frameTime);
}
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Content.Server.Interfaces.GameObjects
{
public interface IPressureProtection
{
public float HighPressureMultiplier { get; }
public float LowPressureMultiplier { get; }
}
}

View File

@@ -158,6 +158,44 @@ namespace Content.Shared.Atmos
public const float PhoronUpperTemperature = (1370f+T0C);
public const float PhoronOxygenFullburn = 10f;
public const float PhoronBurnRateDelta = 9f;
/// <summary>
/// Determines at what pressure the ultra-high pressure red icon is displayed.
/// </summary>
public const float HazardHighPressure = 550f;
/// <summary>
/// Determines when the orange pressure icon is displayed.
/// </summary>
public const float WarningHighPressure = 0.7f * HazardHighPressure;
/// <summary>
/// Determines when the gray low pressure icon is displayed.
/// </summary>
public const float WarningLowPressure = 2.5f * HazardLowPressure;
/// <summary>
/// Determines when the black ultra-low pressure icon is displayed.
/// </summary>
public const float HazardLowPressure = 20f;
/// <summary>
/// The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT,
/// with the maximum of MaxHighPressureDamage.
/// </summary>
public const float PressureDamageCoefficient = 4;
/// <summary>
/// Maximum amount of damage that can be endured with high pressure.
/// </summary>
public const int MaxHighPressureDamage = 4;
/// <summary>
/// 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).
/// </summary>
public const int LowPressureDamage = 4;
}
/// <summary>

View File

@@ -56,6 +56,7 @@ namespace Content.Shared.GameObjects.Components.Mobs
Health,
Hunger,
Thirst,
Pressure,
Stun,
Buckled,
Piloting,

View File

@@ -12,6 +12,7 @@
- type: Hands
- type: MovementSpeedModifier
- type: MovedByPressure
- type: Barotrauma
- type: DamageOnHighSpeedImpact
soundHit: /Audio/Effects/hit_kick.ogg
- type: Hunger

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

View File

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

View File

@@ -45,6 +45,7 @@
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Atmos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=autoconnect/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Barotrauma/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BYOND/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String>
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String>