Airlock Hacking: AutoClose & Safety (#1395)
This commit is contained in:
@@ -62,7 +62,6 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_boltsDown = value;
|
_boltsDown = value;
|
||||||
UpdateWiresStatus();
|
|
||||||
UpdateBoltLightStatus();
|
UpdateBoltLightStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,11 +74,18 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_boltLightsWirePulsed = value;
|
_boltLightsWirePulsed = value;
|
||||||
UpdateWiresStatus();
|
|
||||||
UpdateBoltLightStatus();
|
UpdateBoltLightStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const float AutoCloseDelayFast = 1;
|
||||||
|
// True => AutoCloseDelay; False => AutoCloseDelayFast
|
||||||
|
private bool NormalCloseSpeed
|
||||||
|
{
|
||||||
|
get => CloseSpeed == AutoCloseDelay;
|
||||||
|
set => CloseSpeed = value ? AutoCloseDelay : AutoCloseDelayFast;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateWiresStatus()
|
private void UpdateWiresStatus()
|
||||||
{
|
{
|
||||||
var powerLight = new StatusLightData(Color.Yellow, StatusLightState.On, "POWR");
|
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,
|
var boltLightsStatus = new StatusLightData(Color.Lime,
|
||||||
_boltLightsWirePulsed ? StatusLightState.On : StatusLightState.Off, "BLTL");
|
_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.PowerIndicator, powerLight);
|
||||||
_wires.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
|
_wires.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
|
||||||
_wires.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
|
_wires.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
|
||||||
_wires.SetStatus(3, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
|
_wires.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
|
||||||
_wires.SetStatus(4, new StatusLightData(Color.Orange, StatusLightState.Off, "TIME"));
|
_wires.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
|
||||||
_wires.SetStatus(5, new StatusLightData(Color.Red, StatusLightState.Off, "SAFE"));
|
_wires.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus);
|
||||||
/*
|
/*
|
||||||
_wires.SetStatus(6, powerLight);
|
_wires.SetStatus(6, powerLight);
|
||||||
_wires.SetStatus(7, powerLight);
|
_wires.SetStatus(7, powerLight);
|
||||||
@@ -210,6 +225,23 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
/// Mending causes them to go on again
|
/// Mending causes them to go on again
|
||||||
/// </summary>
|
/// </summary>
|
||||||
BoltLight,
|
BoltLight,
|
||||||
|
|
||||||
|
// Placeholder for when AI is implemented
|
||||||
|
AIControl,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pulsing causes door to close faster
|
||||||
|
/// Cutting disables door timer, causing door to stop closing automatically
|
||||||
|
/// Mending restores door timer
|
||||||
|
/// </summary>
|
||||||
|
Timing,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pulsing toggles safety
|
||||||
|
/// Cutting disables safety
|
||||||
|
/// Mending enables safety
|
||||||
|
/// </summary>
|
||||||
|
Safety,
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterWires(WiresComponent.WiresBuilder builder)
|
public void RegisterWires(WiresComponent.WiresBuilder builder)
|
||||||
@@ -218,8 +250,8 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
builder.CreateWire(Wires.BackupPower);
|
builder.CreateWire(Wires.BackupPower);
|
||||||
builder.CreateWire(Wires.Bolts);
|
builder.CreateWire(Wires.Bolts);
|
||||||
builder.CreateWire(Wires.BoltLight);
|
builder.CreateWire(Wires.BoltLight);
|
||||||
builder.CreateWire(4);
|
builder.CreateWire(Wires.Timing);
|
||||||
builder.CreateWire(5);
|
builder.CreateWire(Wires.Safety);
|
||||||
/*
|
/*
|
||||||
builder.CreateWire(6);
|
builder.CreateWire(6);
|
||||||
builder.CreateWire(7);
|
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
|
// we need to change the property here to set the appearance again
|
||||||
BoltLightsVisible = !_boltLightsWirePulsed;
|
BoltLightsVisible = !_boltLightsWirePulsed;
|
||||||
break;
|
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:
|
case Wires.BoltLight:
|
||||||
BoltLightsVisible = true;
|
BoltLightsVisible = true;
|
||||||
break;
|
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:
|
case Wires.BoltLight:
|
||||||
BoltLightsVisible = false;
|
BoltLightsVisible = false;
|
||||||
break;
|
break;
|
||||||
|
case Wires.Timing:
|
||||||
|
AutoClose = false;
|
||||||
|
break;
|
||||||
|
case Wires.Safety:
|
||||||
|
Safety = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components.Access;
|
using Content.Server.GameObjects.Components.Access;
|
||||||
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
@@ -31,17 +33,25 @@ namespace Content.Server.GameObjects
|
|||||||
set => _state = value;
|
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 CollidableComponent collidableComponent;
|
||||||
private AppearanceComponent _appearance;
|
private AppearanceComponent _appearance;
|
||||||
private CancellationTokenSource _cancellationTokenSource;
|
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 OpenTimeOne = TimeSpan.FromSeconds(0.3f);
|
||||||
private static readonly TimeSpan OpenTimeTwo = TimeSpan.FromSeconds(0.9f);
|
private static readonly TimeSpan OpenTimeTwo = TimeSpan.FromSeconds(0.9f);
|
||||||
private static readonly TimeSpan DenyTime = TimeSpan.FromSeconds(0.45f);
|
private static readonly TimeSpan DenyTime = TimeSpan.FromSeconds(0.45f);
|
||||||
|
|
||||||
|
private const int DoorCrushDamage = 15;
|
||||||
|
private const float DoorStunTime = 5f;
|
||||||
|
protected bool Safety = true;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private bool _occludes;
|
private bool _occludes;
|
||||||
|
|
||||||
@@ -192,27 +202,72 @@ namespace Content.Server.GameObjects
|
|||||||
Close();
|
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()
|
public bool Close()
|
||||||
{
|
{
|
||||||
|
bool shouldCheckCrush = false;
|
||||||
if (collidableComponent.IsColliding(Vector2.Zero, false))
|
if (collidableComponent.IsColliding(Vector2.Zero, false))
|
||||||
{
|
{
|
||||||
// Do nothing, somebody's in the door.
|
if (Safety)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// check if we crush someone while closing
|
||||||
|
shouldCheckCrush = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
State = DoorState.Closing;
|
State = DoorState.Closing;
|
||||||
collidableComponent.Hard = true;
|
|
||||||
OpenTimeCounter = 0;
|
OpenTimeCounter = 0;
|
||||||
SetAppearance(DoorVisualState.Closing);
|
SetAppearance(DoorVisualState.Closing);
|
||||||
|
|
||||||
Timer.Spawn(CloseTime, () =>
|
|
||||||
{
|
|
||||||
State = DoorState.Closed;
|
|
||||||
SetAppearance(DoorVisualState.Closed);
|
|
||||||
if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder))
|
if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder))
|
||||||
{
|
{
|
||||||
occluder.Enabled = true;
|
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);
|
||||||
}, _cancellationTokenSource.Token);
|
}, _cancellationTokenSource.Token);
|
||||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner.Uid, true));
|
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner.Uid, true));
|
||||||
return true;
|
return true;
|
||||||
@@ -232,7 +287,6 @@ namespace Content.Server.GameObjects
|
|||||||
}, _cancellationTokenSource.Token);
|
}, _cancellationTokenSource.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private const float AUTO_CLOSE_DELAY = 5;
|
|
||||||
public virtual void OnUpdate(float frameTime)
|
public virtual void OnUpdate(float frameTime)
|
||||||
{
|
{
|
||||||
if (State != DoorState.Open)
|
if (State != DoorState.Open)
|
||||||
@@ -240,8 +294,12 @@ namespace Content.Server.GameObjects
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AutoClose)
|
||||||
|
{
|
||||||
OpenTimeCounter += frameTime;
|
OpenTimeCounter += frameTime;
|
||||||
if (OpenTimeCounter > AUTO_CLOSE_DELAY)
|
}
|
||||||
|
|
||||||
|
if (OpenTimeCounter > CloseSpeed)
|
||||||
{
|
{
|
||||||
if (!CanClose() || !Close())
|
if (!CanClose() || !Close())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,5 +9,8 @@ namespace Content.Shared.GameObjects.Components.Doors
|
|||||||
PowerIndicator,
|
PowerIndicator,
|
||||||
BoltIndicator,
|
BoltIndicator,
|
||||||
BoltLightIndicator,
|
BoltLightIndicator,
|
||||||
|
AIControlIndicator,
|
||||||
|
TimingIndicator,
|
||||||
|
SafetyIndicator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user