diff --git a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs
index 65f0892c85..855f127dc7 100644
--- a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs
+++ b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs
@@ -62,7 +62,6 @@ namespace Content.Server.GameObjects.Components.Doors
set
{
_boltsDown = value;
- UpdateWiresStatus();
UpdateBoltLightStatus();
}
}
@@ -75,11 +74,18 @@ namespace Content.Server.GameObjects.Components.Doors
set
{
_boltLightsWirePulsed = value;
- UpdateWiresStatus();
UpdateBoltLightStatus();
}
}
+ private const float AutoCloseDelayFast = 1;
+ // True => AutoCloseDelay; False => AutoCloseDelayFast
+ private bool NormalCloseSpeed
+ {
+ get => CloseSpeed == AutoCloseDelay;
+ set => CloseSpeed = value ? AutoCloseDelay : AutoCloseDelayFast;
+ }
+
private void UpdateWiresStatus()
{
var powerLight = new StatusLightData(Color.Yellow, StatusLightState.On, "POWR");
@@ -98,12 +104,21 @@ namespace Content.Server.GameObjects.Components.Doors
var boltLightsStatus = new StatusLightData(Color.Lime,
_boltLightsWirePulsed ? StatusLightState.On : StatusLightState.Off, "BLTL");
+ var timingStatus =
+ new StatusLightData(Color.Orange, !AutoClose ? StatusLightState.Off :
+ !NormalCloseSpeed ? StatusLightState.BlinkingSlow :
+ StatusLightState.On,
+ "TIME");
+
+ var safetyStatus =
+ new StatusLightData(Color.Red, Safety ? StatusLightState.On : StatusLightState.Off, "SAFE");
+
_wires.SetStatus(AirlockWireStatus.PowerIndicator, powerLight);
_wires.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
_wires.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
- _wires.SetStatus(3, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
- _wires.SetStatus(4, new StatusLightData(Color.Orange, StatusLightState.Off, "TIME"));
- _wires.SetStatus(5, new StatusLightData(Color.Red, StatusLightState.Off, "SAFE"));
+ _wires.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
+ _wires.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
+ _wires.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus);
/*
_wires.SetStatus(6, powerLight);
_wires.SetStatus(7, powerLight);
@@ -210,6 +225,23 @@ namespace Content.Server.GameObjects.Components.Doors
/// Mending causes them to go on again
///
BoltLight,
+
+ // Placeholder for when AI is implemented
+ AIControl,
+
+ ///
+ /// Pulsing causes door to close faster
+ /// Cutting disables door timer, causing door to stop closing automatically
+ /// Mending restores door timer
+ ///
+ Timing,
+
+ ///
+ /// Pulsing toggles safety
+ /// Cutting disables safety
+ /// Mending enables safety
+ ///
+ Safety,
}
public void RegisterWires(WiresComponent.WiresBuilder builder)
@@ -218,8 +250,8 @@ namespace Content.Server.GameObjects.Components.Doors
builder.CreateWire(Wires.BackupPower);
builder.CreateWire(Wires.Bolts);
builder.CreateWire(Wires.BoltLight);
- builder.CreateWire(4);
- builder.CreateWire(5);
+ builder.CreateWire(Wires.Timing);
+ builder.CreateWire(Wires.Safety);
/*
builder.CreateWire(6);
builder.CreateWire(7);
@@ -263,6 +295,12 @@ namespace Content.Server.GameObjects.Components.Doors
// we need to change the property here to set the appearance again
BoltLightsVisible = !_boltLightsWirePulsed;
break;
+ case Wires.Timing:
+ NormalCloseSpeed = !NormalCloseSpeed;
+ break;
+ case Wires.Safety:
+ Safety = !Safety;
+ break;
}
}
@@ -279,6 +317,12 @@ namespace Content.Server.GameObjects.Components.Doors
case Wires.BoltLight:
BoltLightsVisible = true;
break;
+ case Wires.Timing:
+ AutoClose = true;
+ break;
+ case Wires.Safety:
+ Safety = true;
+ break;
}
}
@@ -292,6 +336,12 @@ namespace Content.Server.GameObjects.Components.Doors
case Wires.BoltLight:
BoltLightsVisible = false;
break;
+ case Wires.Timing:
+ AutoClose = false;
+ break;
+ case Wires.Safety:
+ Safety = false;
+ break;
}
}
diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
index e922096914..23a2a80ee5 100644
--- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
+++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
@@ -1,5 +1,7 @@
using System;
+using System.Linq;
using Content.Server.GameObjects.Components.Access;
+using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Server.Utility;
@@ -31,17 +33,25 @@ namespace Content.Server.GameObjects
set => _state = value;
}
- private float OpenTimeCounter;
-
+ protected float OpenTimeCounter;
+ protected bool AutoClose = true;
+ protected const float AutoCloseDelay = 5;
+ protected float CloseSpeed = AutoCloseDelay;
+
private CollidableComponent collidableComponent;
private AppearanceComponent _appearance;
private CancellationTokenSource _cancellationTokenSource;
- private static readonly TimeSpan CloseTime = TimeSpan.FromSeconds(1.2f);
+ private static readonly TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.3f);
+ private static readonly TimeSpan CloseTimeTwo = TimeSpan.FromSeconds(0.9f);
private static readonly TimeSpan OpenTimeOne = TimeSpan.FromSeconds(0.3f);
private static readonly TimeSpan OpenTimeTwo = TimeSpan.FromSeconds(0.9f);
private static readonly TimeSpan DenyTime = TimeSpan.FromSeconds(0.45f);
+ private const int DoorCrushDamage = 15;
+ private const float DoorStunTime = 5f;
+ protected bool Safety = true;
+
[ViewVariables]
private bool _occludes;
@@ -192,27 +202,72 @@ namespace Content.Server.GameObjects
Close();
}
+ private void CheckCrush()
+ {
+ // Check if collides with something
+ var collidesWith = collidableComponent.GetCollidingEntities(Vector2.Zero, false);
+ if (collidesWith.Count() != 0)
+ {
+ // Crush
+ bool hitSomeone = false;
+ foreach (var e in collidesWith)
+ {
+ if (!e.TryGetComponent(out StunnableComponent stun)
+ || !e.TryGetComponent(out DamageableComponent damage)
+ || !e.TryGetComponent(out ICollidableComponent otherBody)
+ || !Owner.TryGetComponent(out ICollidableComponent body))
+ continue;
+
+ var percentage = otherBody.WorldAABB.IntersectPercentage(body.WorldAABB);
+
+ if (percentage < 0.1f)
+ continue;
+
+ damage.TakeDamage(Shared.GameObjects.DamageType.Brute, DoorCrushDamage);
+ stun.Paralyze(DoorStunTime);
+ hitSomeone = true;
+ }
+ // If we hit someone, open up after stun (opens right when stun ends)
+ if (hitSomeone)
+ {
+ Timer.Spawn(TimeSpan.FromSeconds(DoorStunTime) - OpenTimeOne - OpenTimeTwo, () => Open());
+ }
+ }
+ }
+
public bool Close()
{
+ bool shouldCheckCrush = false;
if (collidableComponent.IsColliding(Vector2.Zero, false))
{
- // Do nothing, somebody's in the door.
- return false;
+ if (Safety)
+ return false;
+
+ // check if we crush someone while closing
+ shouldCheckCrush = true;
}
State = DoorState.Closing;
- collidableComponent.Hard = true;
OpenTimeCounter = 0;
SetAppearance(DoorVisualState.Closing);
-
- Timer.Spawn(CloseTime, () =>
+ if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder))
{
+ occluder.Enabled = true;
+ }
+
+ Timer.Spawn(CloseTimeOne, async () =>
+ {
+ if (shouldCheckCrush)
+ {
+ CheckCrush();
+ }
+
+ collidableComponent.Hard = true;
+
+ await Timer.Delay(CloseTimeTwo, _cancellationTokenSource.Token);
+
State = DoorState.Closed;
SetAppearance(DoorVisualState.Closed);
- if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder))
- {
- occluder.Enabled = true;
- }
}, _cancellationTokenSource.Token);
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner.Uid, true));
return true;
@@ -232,7 +287,6 @@ namespace Content.Server.GameObjects
}, _cancellationTokenSource.Token);
}
- private const float AUTO_CLOSE_DELAY = 5;
public virtual void OnUpdate(float frameTime)
{
if (State != DoorState.Open)
@@ -240,8 +294,12 @@ namespace Content.Server.GameObjects
return;
}
- OpenTimeCounter += frameTime;
- if (OpenTimeCounter > AUTO_CLOSE_DELAY)
+ if (AutoClose)
+ {
+ OpenTimeCounter += frameTime;
+ }
+
+ if (OpenTimeCounter > CloseSpeed)
{
if (!CanClose() || !Close())
{
diff --git a/Content.Shared/GameObjects/Components/Doors/AirlockWireStatus.cs b/Content.Shared/GameObjects/Components/Doors/AirlockWireStatus.cs
index b2833d6abf..bafe35c625 100644
--- a/Content.Shared/GameObjects/Components/Doors/AirlockWireStatus.cs
+++ b/Content.Shared/GameObjects/Components/Doors/AirlockWireStatus.cs
@@ -9,5 +9,8 @@ namespace Content.Shared.GameObjects.Components.Doors
PowerIndicator,
BoltIndicator,
BoltLightIndicator,
+ AIControlIndicator,
+ TimingIndicator,
+ SafetyIndicator,
}
}