diff --git a/Content.Client/Doors/AirlockVisualizer.cs b/Content.Client/Doors/AirlockVisualizer.cs
index 8f6c0651b1..a428a5bc2e 100644
--- a/Content.Client/Doors/AirlockVisualizer.cs
+++ b/Content.Client/Doors/AirlockVisualizer.cs
@@ -17,15 +17,6 @@ namespace Content.Client.Doors
{
private const string AnimationKey = "airlock_animation";
- [DataField("open_sound", required: true)]
- private string _openSound = default!;
-
- [DataField("close_sound", required: true)]
- private string _closeSound = default!;
-
- [DataField("deny_sound", required: true)]
- private string _denySound = default!;
-
[DataField("animation_time")]
private float _delay = 0.8f;
@@ -51,14 +42,6 @@ namespace Content.Client.Doors
CloseAnimation.AnimationTracks.Add(flickMaintenancePanel);
flickMaintenancePanel.LayerKey = WiresVisualizer.WiresVisualLayers.MaintenancePanel;
flickMaintenancePanel.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("panel_closing", 0f));
-
- var sound = new AnimationTrackPlaySound();
- CloseAnimation.AnimationTracks.Add(sound);
-
- if (_closeSound != null)
- {
- sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(_closeSound, 0));
- }
}
OpenAnimation = new Animation {Length = TimeSpan.FromSeconds(_delay)};
@@ -80,11 +63,6 @@ namespace Content.Client.Doors
var sound = new AnimationTrackPlaySound();
OpenAnimation.AnimationTracks.Add(sound);
-
- if (_openSound != null)
- {
- sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(_openSound, 0));
- }
}
DenyAnimation = new Animation {Length = TimeSpan.FromSeconds(0.3f)};
@@ -96,11 +74,6 @@ namespace Content.Client.Doors
var sound = new AnimationTrackPlaySound();
DenyAnimation.AnimationTracks.Add(sound);
-
- if (_denySound != null)
- {
- sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(_denySound, 0, () => AudioHelpers.WithVariation(0.05f)));
- }
}
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs
index 30b4df6473..87a4f8b2e1 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs
@@ -5,6 +5,7 @@ using System.Buffers;
using System.Collections.Generic;
using Content.Server.Atmos.Components;
using Content.Server.Coordinates.Helpers;
+using Content.Server.Doors.Components;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
diff --git a/Content.Server/Doors/Components/AirlockComponent.cs b/Content.Server/Doors/Components/AirlockComponent.cs
index 2e47a1b6d7..dda64b4cda 100644
--- a/Content.Server/Doors/Components/AirlockComponent.cs
+++ b/Content.Server/Doors/Components/AirlockComponent.cs
@@ -7,12 +7,14 @@ using Content.Shared.Doors;
using Content.Shared.Interaction;
using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
+using Content.Shared.Sound;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Player;
+using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using static Content.Shared.Wires.SharedWiresComponent;
using static Content.Shared.Wires.SharedWiresComponent.WiresAction;
@@ -23,30 +25,41 @@ namespace Content.Server.Doors.Components
/// Companion component to ServerDoorComponent that handles airlock-specific behavior -- wires, requiring power to operate, bolts, and allowing automatic closing.
///
[RegisterComponent]
- [ComponentReference(typeof(IDoorCheck))]
- public class AirlockComponent : Component, IWires, IDoorCheck
+ public class AirlockComponent : Component, IWires
{
public override string Name => "Airlock";
[ComponentDependency]
- private readonly ServerDoorComponent? _doorComponent = null;
+ public readonly ServerDoorComponent? DoorComponent = null;
[ComponentDependency]
- private readonly SharedAppearanceComponent? _appearanceComponent = null;
+ public readonly SharedAppearanceComponent? AppearanceComponent = null;
[ComponentDependency]
- private readonly ApcPowerReceiverComponent? _receiverComponent = null;
+ public readonly ApcPowerReceiverComponent? ReceiverComponent = null;
[ComponentDependency]
- private readonly WiresComponent? _wiresComponent = null;
+ public readonly WiresComponent? WiresComponent = null;
+
+ ///
+ /// Sound to play when the bolts on the airlock go up.
+ ///
+ [DataField("boltUpSound")]
+ public SoundSpecifier BoltUpSound = new SoundPathSpecifier("/Audio/Machines/boltsup.ogg");
+
+ ///
+ /// Sound to play when the bolts on the airlock go down.
+ ///
+ [DataField("boltDownSound")]
+ public SoundSpecifier BoltDownSound = new SoundPathSpecifier("/Audio/Machines/boltsdown.ogg");
///
/// Duration for which power will be disabled after pulsing either power wire.
///
- private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0);
+ [DataField("powerWiresTimeout")]
+ public float PowerWiresTimeout = 5.0f;
private CancellationTokenSource _powerWiresPulsedTimerCancel = new();
-
private bool _powerWiresPulsed;
///
@@ -83,7 +96,7 @@ namespace Content.Server.Doors.Components
private bool BoltLightsVisible
{
get => _boltLightsWirePulsed && BoltsDown && IsPowered()
- && _doorComponent != null && _doorComponent.State == SharedDoorComponent.DoorState.Closed;
+ && DoorComponent != null && DoorComponent.State == SharedDoorComponent.DoorState.Closed;
set
{
_boltLightsWirePulsed = value;
@@ -91,120 +104,53 @@ namespace Content.Server.Doors.Components
}
}
- private static readonly TimeSpan AutoCloseDelayFast = TimeSpan.FromSeconds(1);
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("autoClose")]
+ public bool AutoClose = true;
[ViewVariables(VVAccess.ReadWrite)]
- private bool _autoClose = true;
+ [DataField("autoCloseDelayModifier")]
+ public float AutoCloseDelayModifier = 1.0f;
[ViewVariables(VVAccess.ReadWrite)]
- private bool _normalCloseSpeed = true;
-
- [ViewVariables(VVAccess.ReadWrite)]
- private bool _safety = true;
+ public bool Safety = true;
protected override void Initialize()
{
base.Initialize();
- if (_receiverComponent != null && _appearanceComponent != null)
+ if (ReceiverComponent != null && AppearanceComponent != null)
{
- _appearanceComponent.SetData(DoorVisuals.Powered, _receiverComponent.Powered);
+ AppearanceComponent.SetData(DoorVisuals.Powered, ReceiverComponent.Powered);
}
}
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PowerChangedMessage powerChanged:
- PowerDeviceOnOnPowerStateChanged(powerChanged);
- break;
- }
- }
-
- void IDoorCheck.OnStateChange(SharedDoorComponent.DoorState doorState)
- {
- // Only show the maintenance panel if the airlock is closed
- if (_wiresComponent != null)
- {
- _wiresComponent.IsPanelVisible = doorState != SharedDoorComponent.DoorState.Open;
- }
- // If the door is closed, we should look if the bolt was locked while closing
- UpdateBoltLightStatus();
- }
-
- bool IDoorCheck.OpenCheck() => CanChangeState();
-
- bool IDoorCheck.CloseCheck() => CanChangeState();
-
- bool IDoorCheck.DenyCheck() => CanChangeState();
-
- bool IDoorCheck.SafetyCheck() => _safety;
-
- bool IDoorCheck.AutoCloseCheck() => _autoClose;
-
- TimeSpan? IDoorCheck.GetCloseSpeed()
- {
- if (_normalCloseSpeed)
- {
- return null;
- }
- return AutoCloseDelayFast;
- }
-
- bool IDoorCheck.BlockActivate(ActivateEventArgs eventArgs)
- {
- if (_wiresComponent != null && _wiresComponent.IsPanelOpen &&
- eventArgs.User.TryGetComponent(out ActorComponent? actor))
- {
- _wiresComponent.OpenInterface(actor.PlayerSession);
- return true;
- }
- return false;
- }
-
- bool IDoorCheck.CanPryCheck(InteractUsingEventArgs eventArgs)
- {
- if (IsBolted())
- {
- Owner.PopupMessage(eventArgs.User, Loc.GetString("airlock-component-cannot-pry-is-bolted-message "));
- return false;
- }
- if (IsPowered())
- {
- Owner.PopupMessage(eventArgs.User, Loc.GetString("airlock-component-cannot-pry-is-powered-message"));
- return false;
- }
- return true;
- }
-
- private bool CanChangeState()
+ public bool CanChangeState()
{
return IsPowered() && !IsBolted();
}
- private bool IsBolted()
+ public bool IsBolted()
{
return _boltsDown;
}
- private bool IsPowered()
+ public bool IsPowered()
{
- return _receiverComponent == null || _receiverComponent.Powered;
+ return ReceiverComponent == null || ReceiverComponent.Powered;
}
- private void UpdateBoltLightStatus()
+ public void UpdateBoltLightStatus()
{
- if (_appearanceComponent != null)
+ if (AppearanceComponent != null)
{
- _appearanceComponent.SetData(DoorVisuals.BoltLights, BoltLightsVisible);
+ AppearanceComponent.SetData(DoorVisuals.BoltLights, BoltLightsVisible);
}
}
- private void UpdateWiresStatus()
+ public void UpdateWiresStatus()
{
- if (_doorComponent == null)
+ if (DoorComponent == null)
{
return;
}
@@ -214,9 +160,9 @@ namespace Content.Server.Doors.Components
{
powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR");
}
- else if (_wiresComponent != null &&
- _wiresComponent.IsWireCut(Wires.MainPower) &&
- _wiresComponent.IsWireCut(Wires.BackupPower))
+ else if (WiresComponent != null &&
+ WiresComponent.IsWireCut(Wires.MainPower) &&
+ WiresComponent.IsWireCut(Wires.BackupPower))
{
powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR");
}
@@ -226,63 +172,59 @@ namespace Content.Server.Doors.Components
var boltLightsStatus = new StatusLightData(Color.Lime,
_boltLightsWirePulsed ? StatusLightState.On : StatusLightState.Off, "BLTL");
+ var ev = new DoorGetCloseTimeModifierEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+
var timingStatus =
- new StatusLightData(Color.Orange, !_autoClose ? StatusLightState.Off :
- !_normalCloseSpeed ? StatusLightState.BlinkingSlow :
+ new StatusLightData(Color.Orange, !AutoClose ? StatusLightState.Off :
+ !MathHelper.CloseTo(ev.CloseTimeModifier, 1.0f) ? StatusLightState.BlinkingSlow :
StatusLightState.On,
"TIME");
var safetyStatus =
- new StatusLightData(Color.Red, _safety ? StatusLightState.On : StatusLightState.Off, "SAFE");
+ new StatusLightData(Color.Red, Safety ? StatusLightState.On : StatusLightState.Off, "SAFE");
- if (_wiresComponent == null)
+ if (WiresComponent == null)
{
return;
}
- _wiresComponent.SetStatus(AirlockWireStatus.PowerIndicator, powerLight);
- _wiresComponent.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
- _wiresComponent.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
- _wiresComponent.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
- _wiresComponent.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
- _wiresComponent.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus);
- /*
- _wires.SetStatus(6, powerLight);
- _wires.SetStatus(7, powerLight);
- _wires.SetStatus(8, powerLight);
- _wires.SetStatus(9, powerLight);
- _wires.SetStatus(10, powerLight);
- _wires.SetStatus(11, powerLight);*/
+ WiresComponent.SetStatus(AirlockWireStatus.PowerIndicator, powerLight);
+ WiresComponent.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
+ WiresComponent.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
+ WiresComponent.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
+ WiresComponent.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
+ WiresComponent.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus);
}
private void UpdatePowerCutStatus()
{
- if (_receiverComponent == null)
+ if (ReceiverComponent == null)
{
return;
}
if (PowerWiresPulsed)
{
- _receiverComponent.PowerDisabled = true;
+ ReceiverComponent.PowerDisabled = true;
return;
}
- if (_wiresComponent == null)
+ if (WiresComponent == null)
{
return;
}
- _receiverComponent.PowerDisabled =
- _wiresComponent.IsWireCut(Wires.MainPower) ||
- _wiresComponent.IsWireCut(Wires.BackupPower);
+ ReceiverComponent.PowerDisabled =
+ WiresComponent.IsWireCut(Wires.MainPower) ||
+ WiresComponent.IsWireCut(Wires.BackupPower);
}
private void PowerDeviceOnOnPowerStateChanged(PowerChangedMessage e)
{
- if (_appearanceComponent != null)
+ if (AppearanceComponent != null)
{
- _appearanceComponent.SetData(DoorVisuals.Powered, e.Powered);
+ AppearanceComponent.SetData(DoorVisuals.Powered, e.Powered);
}
// BoltLights also got out
@@ -341,19 +283,13 @@ namespace Content.Server.Doors.Components
builder.CreateWire(Wires.BoltLight);
builder.CreateWire(Wires.Timing);
builder.CreateWire(Wires.Safety);
- /*
- builder.CreateWire(6);
- builder.CreateWire(7);
- builder.CreateWire(8);
- builder.CreateWire(9);
- builder.CreateWire(10);
- builder.CreateWire(11);*/
+
UpdateWiresStatus();
}
public void WiresUpdate(WiresUpdateEventArgs args)
{
- if(_doorComponent == null)
+ if(DoorComponent == null)
{
return;
}
@@ -367,7 +303,7 @@ namespace Content.Server.Doors.Components
PowerWiresPulsed = true;
_powerWiresPulsedTimerCancel.Cancel();
_powerWiresPulsedTimerCancel = new CancellationTokenSource();
- Owner.SpawnTimer(PowerWiresTimeout,
+ Owner.SpawnTimer(TimeSpan.FromSeconds(PowerWiresTimeout),
() => PowerWiresPulsed = false,
_powerWiresPulsedTimerCancel.Token);
break;
@@ -390,11 +326,11 @@ namespace Content.Server.Doors.Components
BoltLightsVisible = !_boltLightsWirePulsed;
break;
case Wires.Timing:
- _normalCloseSpeed = !_normalCloseSpeed;
- _doorComponent.RefreshAutoClose();
+ AutoCloseDelayModifier = 0.5f;
+ DoorComponent.RefreshAutoClose();
break;
case Wires.Safety:
- _safety = !_safety;
+ Safety = !Safety;
break;
}
}
@@ -413,11 +349,11 @@ namespace Content.Server.Doors.Components
BoltLightsVisible = true;
break;
case Wires.Timing:
- _autoClose = true;
- _doorComponent.RefreshAutoClose();
+ AutoClose = true;
+ DoorComponent.RefreshAutoClose();
break;
case Wires.Safety:
- _safety = true;
+ Safety = true;
break;
}
}
@@ -433,11 +369,11 @@ namespace Content.Server.Doors.Components
BoltLightsVisible = false;
break;
case Wires.Timing:
- _autoClose = false;
- _doorComponent.RefreshAutoClose();
+ AutoClose = false;
+ DoorComponent.RefreshAutoClose();
break;
case Wires.Safety:
- _safety = false;
+ Safety = false;
break;
}
}
@@ -455,7 +391,7 @@ namespace Content.Server.Doors.Components
BoltsDown = newBolts;
- SoundSystem.Play(Filter.Broadcast(), newBolts ? "/Audio/Machines/boltsdown.ogg" : "/Audio/Machines/boltsup.ogg", Owner);
+ SoundSystem.Play(Filter.Broadcast(), newBolts ? BoltDownSound.GetSound() : BoltUpSound.GetSound(), Owner);
}
}
}
diff --git a/Content.Server/Atmos/Components/FirelockComponent.cs b/Content.Server/Doors/Components/FirelockComponent.cs
similarity index 59%
rename from Content.Server/Atmos/Components/FirelockComponent.cs
rename to Content.Server/Doors/Components/FirelockComponent.cs
index b1849cd757..ee7154bb28 100644
--- a/Content.Server/Atmos/Components/FirelockComponent.cs
+++ b/Content.Server/Doors/Components/FirelockComponent.cs
@@ -1,3 +1,4 @@
+using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Doors;
using Content.Server.Doors.Components;
@@ -6,26 +7,34 @@ using Content.Shared.Interaction;
using Content.Shared.Notification.Managers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
+using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Server.Atmos.Components
+namespace Content.Server.Doors.Components
{
///
- /// Companion component to ServerDoorComponent that handles firelock-specific behavior -- primarily prying, and not being openable on open-hand click.
+ /// Companion component to ServerDoorComponent that handles firelock-specific behavior -- primarily prying,
+ /// and not being openable on open-hand click.
///
[RegisterComponent]
- [ComponentReference(typeof(IDoorCheck))]
- public class FirelockComponent : Component, IDoorCheck
+ public class FirelockComponent : Component
{
public override string Name => "Firelock";
[ComponentDependency]
- private readonly ServerDoorComponent? _doorComponent = null;
+ public readonly ServerDoorComponent? DoorComponent = null;
+
+ ///
+ /// Pry time modifier to be used when the firelock is currently closed due to fire or pressure.
+ ///
+ ///
+ [DataField("lockedPryTimeModifier")]
+ public float LockedPryTimeModifier = 1.5f;
public bool EmergencyPressureStop()
{
- if (_doorComponent != null && _doorComponent.State == SharedDoorComponent.DoorState.Open && _doorComponent.CanCloseGeneric())
+ if (DoorComponent != null && DoorComponent.State == SharedDoorComponent.DoorState.Open && DoorComponent.CanCloseGeneric())
{
- _doorComponent.Close();
+ DoorComponent.Close();
if (Owner.TryGetComponent(out AirtightComponent? airtight))
{
EntitySystem.Get().SetAirblocked(airtight, true);
@@ -35,41 +44,6 @@ namespace Content.Server.Atmos.Components
return false;
}
- bool IDoorCheck.OpenCheck()
- {
- return !IsHoldingFire() && !IsHoldingPressure();
- }
-
- bool IDoorCheck.DenyCheck() => false;
-
- float? IDoorCheck.GetPryTime()
- {
- if (IsHoldingFire() || IsHoldingPressure())
- {
- return 1.5f;
- }
- return null;
- }
-
- bool IDoorCheck.BlockActivate(ActivateEventArgs eventArgs) => true;
-
- void IDoorCheck.OnStartPry(InteractUsingEventArgs eventArgs)
- {
- if (_doorComponent == null || _doorComponent.State != SharedDoorComponent.DoorState.Closed)
- {
- return;
- }
-
- if (IsHoldingPressure())
- {
- Owner.PopupMessage(eventArgs.User, Loc.GetString("firelock-component-is-holding-pressure-message"));
- }
- else if (IsHoldingFire())
- {
- Owner.PopupMessage(eventArgs.User, Loc.GetString("firelock-component-is-holding-fire-message"));
- }
- }
-
public bool IsHoldingPressure(float threshold = 20)
{
var atmosphereSystem = EntitySystem.Get();
diff --git a/Content.Server/Doors/Components/ServerDoorComponent.cs b/Content.Server/Doors/Components/ServerDoorComponent.cs
index 8449074d65..1feb49a3b6 100644
--- a/Content.Server/Doors/Components/ServerDoorComponent.cs
+++ b/Content.Server/Doors/Components/ServerDoorComponent.cs
@@ -14,6 +14,7 @@ using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Doors;
using Content.Shared.Interaction;
+using Content.Shared.Sound;
using Content.Shared.Tool;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
@@ -37,9 +38,6 @@ namespace Content.Server.Doors.Components
[ComponentReference(typeof(SharedDoorComponent))]
public class ServerDoorComponent : SharedDoorComponent, IActivate, IInteractUsing, IMapInit
{
- [ComponentDependency]
- private readonly IDoorCheck? _doorCheck = null;
-
[ViewVariables]
[DataField("board")]
private string? _boardPrototype;
@@ -63,11 +61,8 @@ namespace Content.Server.Doors.Components
_ => throw new ArgumentOutOfRangeException(),
};
- if (_doorCheck != null)
- {
- _doorCheck.OnStateChange(State);
- RefreshAutoClose();
- }
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new DoorStateChangedEvent(State), false);
+ _autoCloseCancelTokenSource?.Cancel();
Dirty();
}
@@ -105,7 +100,7 @@ namespace Content.Server.Doors.Components
/// Handled in Startup().
///
[ViewVariables(VVAccess.ReadWrite)] [DataField("startOpen")]
- private bool _startOpen;
+ private bool _startOpen = false;
///
/// Whether the airlock is welded shut. Can be set by the prototype, although this will fail if the door isn't weldable.
@@ -139,6 +134,41 @@ namespace Content.Server.Doors.Components
[DataField("weldable")]
private bool _weldable = true;
+ ///
+ /// Sound to play when the door opens.
+ ///
+ [DataField("openSound")]
+ public SoundSpecifier? OpenSound;
+
+ ///
+ /// Sound to play when the door closes.
+ ///
+ [DataField("closeSound")]
+ public SoundSpecifier? CloseSound;
+
+ ///
+ /// Sound to play if the door is denied.
+ ///
+ [DataField("denySound")]
+ public SoundSpecifier? DenySound;
+
+ ///
+ /// Default time that the door should take to pry open.
+ ///
+ [DataField("pryTime")]
+ public float PryTime = 0.5f;
+
+ ///
+ /// Minimum interval allowed between deny sounds in milliseconds.
+ ///
+ [DataField("denySoundMinimumInterval")]
+ public float DenySoundMinimumInterval = 250.0f;
+
+ ///
+ /// Used to stop people from spamming the deny sound.
+ ///
+ private TimeSpan LastDenySoundTime = TimeSpan.Zero;
+
///
/// Whether the door can currently be welded.
///
@@ -149,6 +179,7 @@ namespace Content.Server.Doors.Components
///
private bool _beingWelded;
+
//[ViewVariables(VVAccess.ReadWrite)]
//[DataField("canCrush")]
//private bool _canCrush = true; // TODO implement door crushing
@@ -187,7 +218,7 @@ namespace Content.Server.Doors.Components
Logger.Warning("{0} prototype loaded with incompatible flags: 'welded' and 'startOpen' are both true.", Owner.Name);
return;
}
- QuickOpen();
+ QuickOpen(false);
}
CreateDoorElectronicsBoard();
@@ -195,10 +226,10 @@ namespace Content.Server.Doors.Components
void IActivate.Activate(ActivateEventArgs eventArgs)
{
- if (_doorCheck != null && _doorCheck.BlockActivate(eventArgs))
- {
+ DoorClickShouldActivateEvent ev = new DoorClickShouldActivateEvent(eventArgs);
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+ if (ev.Handled)
return;
- }
if (State == DoorState.Open)
{
@@ -279,12 +310,10 @@ namespace Content.Server.Doors.Components
{
return false;
}
- if(_doorCheck != null)
- {
- return _doorCheck.OpenCheck();
- }
- return true;
+ var ev = new BeforeDoorOpenedEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+ return !ev.Cancelled;
}
///
@@ -301,12 +330,19 @@ namespace Content.Server.Doors.Components
_stateChangeCancelTokenSource?.Cancel();
_stateChangeCancelTokenSource = new();
+ if (OpenSound != null)
+ {
+ SoundSystem.Play(Filter.Pvs(Owner), OpenSound.GetSound(),
+ AudioParams.Default.WithVolume(-5));
+ }
+
Owner.SpawnTimer(OpenTimeOne, async () =>
{
OnPartialOpen();
await Timer.Delay(OpenTimeTwo, _stateChangeCancelTokenSource.Token);
State = DoorState.Open;
+ RefreshAutoClose();
}, _stateChangeCancelTokenSource.Token);
}
@@ -320,7 +356,7 @@ namespace Content.Server.Doors.Components
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner, false));
}
- private void QuickOpen()
+ private void QuickOpen(bool refresh)
{
if (Occludes && Owner.TryGetComponent(out OccluderComponent? occluder))
{
@@ -328,6 +364,8 @@ namespace Content.Server.Doors.Components
}
OnPartialOpen();
State = DoorState.Open;
+ if(refresh)
+ RefreshAutoClose();
}
#endregion
@@ -366,17 +404,19 @@ namespace Content.Server.Doors.Components
/// Boolean describing whether this door can close.
public bool CanCloseGeneric()
{
- if (_doorCheck != null && !_doorCheck.CloseCheck())
- {
+ var ev = new BeforeDoorClosedEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+ if (ev.Cancelled)
return false;
- }
return !IsSafetyColliding();
}
private bool SafetyCheck()
{
- return (_doorCheck != null && _doorCheck.SafetyCheck()) || _inhibitCrush;
+ var ev = new DoorSafetyEnabledEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+ return ev.Safety || _inhibitCrush;
}
///
@@ -412,6 +452,13 @@ namespace Content.Server.Doors.Components
_stateChangeCancelTokenSource?.Cancel();
_stateChangeCancelTokenSource = new();
+
+ if (CloseSound != null)
+ {
+ SoundSystem.Play(Filter.Pvs(Owner), CloseSound.GetSound(),
+ AudioParams.Default.WithVolume(-10));
+ }
+
Owner.SpawnTimer(CloseTimeOne, async () =>
{
// if somebody walked into the door as it was closing, and we don't crush things
@@ -504,10 +551,10 @@ namespace Content.Server.Doors.Components
public void Deny()
{
- if (_doorCheck != null && !_doorCheck.DenyCheck())
- {
+ var ev = new BeforeDoorDeniedEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+ if (ev.Cancelled)
return;
- }
if (State == DoorState.Open || IsWeldedShut)
return;
@@ -515,6 +562,25 @@ namespace Content.Server.Doors.Components
_stateChangeCancelTokenSource?.Cancel();
_stateChangeCancelTokenSource = new();
SetAppearance(DoorVisualState.Deny);
+
+ if (DenySound != null)
+ {
+ if (LastDenySoundTime == TimeSpan.Zero)
+ {
+ LastDenySoundTime = _gameTiming.CurTime;
+ }
+ else
+ {
+ var difference = _gameTiming.CurTime - LastDenySoundTime;
+ if (difference < TimeSpan.FromMilliseconds(DenySoundMinimumInterval))
+ return;
+ }
+
+ LastDenySoundTime = _gameTiming.CurTime;
+ SoundSystem.Play(Filter.Pvs(Owner), DenySound.GetSound(),
+ AudioParams.Default.WithVolume(-3));
+ }
+
Owner.SpawnTimer(DenyTime, () =>
{
SetAppearance(DoorVisualState.Closed);
@@ -522,19 +588,24 @@ namespace Content.Server.Doors.Components
}
///
- /// Stops the current auto-close timer if there is one. Starts a new one if this is appropriate (i.e. entity has an IDoorCheck component that allows auto-closing).
+ /// Starts a new auto close timer if this is appropriate
+ /// (i.e. event raised is not cancelled).
///
public void RefreshAutoClose()
{
- _autoCloseCancelTokenSource?.Cancel();
-
- if (State != DoorState.Open || _doorCheck == null || !_doorCheck.AutoCloseCheck())
- {
+ if (State != DoorState.Open)
return;
- }
+
+ var autoev = new BeforeDoorAutoCloseEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, autoev, false);
+ if (autoev.Cancelled)
+ return;
+
_autoCloseCancelTokenSource = new();
- var realCloseTime = _doorCheck.GetCloseSpeed() ?? AutoCloseDelay;
+ var ev = new DoorGetCloseTimeModifierEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
+ var realCloseTime = AutoCloseDelay * ev.CloseTimeModifier;
Owner.SpawnRepeatingTimer(realCloseTime, async () =>
{
@@ -556,21 +627,18 @@ namespace Content.Server.Doors.Components
// for prying doors
if (tool.HasQuality(ToolQuality.Prying) && !IsWeldedShut)
{
- var successfulPry = false;
+ var ev = new DoorGetPryTimeModifierEvent();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
- if (_doorCheck != null)
- {
- _doorCheck.OnStartPry(eventArgs);
- successfulPry = await tool.UseTool(eventArgs.User, Owner,
- _doorCheck.GetPryTime() ?? 0.5f, ToolQuality.Prying, () => _doorCheck.CanPryCheck(eventArgs));
- }
- else
- {
- successfulPry = await tool.UseTool(eventArgs.User, Owner, 0.5f, ToolQuality.Prying);
- }
+ var canEv = new BeforeDoorPryEvent(eventArgs);
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, canEv, false);
+
+ var successfulPry = await tool.UseTool(eventArgs.User, Owner,
+ ev.PryTimeModifier * PryTime, ToolQuality.Prying, () => !canEv.Cancelled);
if (successfulPry && !IsWeldedShut)
{
+ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new OnDoorPryEvent(eventArgs), false);
if (State == DoorState.Closed)
{
Open();
diff --git a/Content.Server/Doors/DoorEvents.cs b/Content.Server/Doors/DoorEvents.cs
new file mode 100644
index 0000000000..73a0986664
--- /dev/null
+++ b/Content.Server/Doors/DoorEvents.cs
@@ -0,0 +1,141 @@
+#nullable enable
+using System;
+using Content.Shared.Doors;
+using Content.Shared.Interaction;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Doors
+{
+ ///
+ /// Raised when the door's State variable is changed to a new variable that it was not equal to before.
+ ///
+ public class DoorStateChangedEvent : EntityEventArgs
+ {
+ public SharedDoorComponent.DoorState State;
+
+ public DoorStateChangedEvent(SharedDoorComponent.DoorState state)
+ {
+ State = state;
+ }
+ }
+
+ ///
+ /// Raised when the door is determining whether it is able to open.
+ /// Cancel to stop the door from being opened.
+ ///
+ public class BeforeDoorOpenedEvent : CancellableEntityEventArgs
+ {
+ }
+
+ ///
+ /// Raised when the door is successfully opened.
+ ///
+ public class OnDoorOpenedEvent : HandledEntityEventArgs
+ {
+ }
+
+ ///
+ /// Raised when the door is determining whether it is able to close.
+ /// Cancel to stop the door from being closed.
+ ///
+ public class BeforeDoorClosedEvent : CancellableEntityEventArgs
+ {
+ }
+
+ ///
+ /// Raised when the door is successfully closed.
+ ///
+ public class OnDoorClosedEvent : HandledEntityEventArgs
+ {
+ }
+
+ ///
+ /// Called when the door is determining whether it is able to deny.
+ /// Cancel to stop the door from being able to deny.
+ ///
+ public class BeforeDoorDeniedEvent : CancellableEntityEventArgs
+ {
+ }
+
+ ///
+ /// Raised when access to the door is denied.
+ ///
+ public class OnDoorDeniedEvent : HandledEntityEventArgs
+ {
+ }
+
+ ///
+ /// Raised to determine whether the door's safety is on.
+ /// Modify Safety to set the door's safety.
+ ///
+ public class DoorSafetyEnabledEvent : HandledEntityEventArgs
+ {
+ public bool Safety = false;
+ }
+
+ ///
+ /// Raised to determine whether the door should automatically close.
+ /// Cancel to stop it from automatically closing.
+ ///
+ public class BeforeDoorAutoCloseEvent : CancellableEntityEventArgs
+ {
+ }
+
+ ///
+ /// Raised to determine how long the door's pry time should be modified by.
+ /// Multiply PryTimeModifier by the desired amount.
+ ///
+ public class DoorGetPryTimeModifierEvent : EntityEventArgs
+ {
+ public float PryTimeModifier = 1.0f;
+ }
+
+ ///
+ /// Raised to determine how long the door's close time should be modified by.
+ /// Multiply CloseTimeModifier by the desired amount.
+ ///
+ public class DoorGetCloseTimeModifierEvent : EntityEventArgs
+ {
+ public float CloseTimeModifier = 1.0f;
+ }
+
+ ///
+ /// Raised to determine whether clicking the door should open/close it.
+ ///
+ public class DoorClickShouldActivateEvent : HandledEntityEventArgs
+ {
+ public ActivateEventArgs Args;
+
+ public DoorClickShouldActivateEvent(ActivateEventArgs args)
+ {
+ Args = args;
+ }
+ }
+
+ ///
+ /// Raised when an attempt to pry open the door is made.
+ /// Cancel to stop the door from being pried open.
+ ///
+ public class BeforeDoorPryEvent : CancellableEntityEventArgs
+ {
+ public InteractUsingEventArgs Args;
+
+ public BeforeDoorPryEvent(InteractUsingEventArgs args)
+ {
+ Args = args;
+ }
+ }
+
+ ///
+ /// Raised when a door is successfully pried open.
+ ///
+ public class OnDoorPryEvent : EntityEventArgs
+ {
+ public InteractUsingEventArgs Args;
+
+ public OnDoorPryEvent(InteractUsingEventArgs args)
+ {
+ Args = args;
+ }
+ }
+}
diff --git a/Content.Server/Doors/IDoorCheck.cs b/Content.Server/Doors/IDoorCheck.cs
deleted file mode 100644
index 3c5989a5d8..0000000000
--- a/Content.Server/Doors/IDoorCheck.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System;
-using Content.Shared.Doors;
-using Content.Shared.Interaction;
-
-namespace Content.Server.Doors
-{
- public interface IDoorCheck
- {
- ///
- /// Called when the door's State variable is changed to a new variable that it was not equal to before.
- ///
- void OnStateChange(SharedDoorComponent.DoorState doorState) { }
-
- ///
- /// Called when the door is determining whether it is able to open.
- ///
- /// True if the door should open, false if it should not.
- bool OpenCheck() => true;
-
- ///
- /// Called when the door is determining whether it is able to close.
- ///
- /// True if the door should close, false if it should not.
- bool CloseCheck() => true;
-
- ///
- /// Called when the door is determining whether it is able to deny.
- ///
- /// True if the door should deny, false if it should not.
- bool DenyCheck() => true;
-
- ///
- /// Whether the door's safety is on.
- ///
- /// True if safety is on, false if it is not.
- bool SafetyCheck() => false;
-
- ///
- /// Whether the door should close automatically.
- ///
- /// True if the door should close automatically, false if it should not.
- bool AutoCloseCheck() => false;
-
- ///
- /// Gets an override for the amount of time to pry open the door, or null if there is no override.
- ///
- /// Float if there is an override, null otherwise.
- float? GetPryTime() => null;
-
- ///
- /// Gets an override for the amount of time before the door automatically closes, or null if there is no override.
- ///
- /// TimeSpan if there is an override, null otherwise.
- TimeSpan? GetCloseSpeed() => null;
-
- ///
- /// A check to determine whether or not a click on the door should interact with it with the intent to open/close.
- ///
- /// True if the door's IActivate should not run, false otherwise.
- bool BlockActivate(ActivateEventArgs eventArgs) => false;
-
- ///
- /// Called when somebody begins to pry open the door.
- ///
- /// The eventArgs of the InteractUsing method that called this function.
- void OnStartPry(InteractUsingEventArgs eventArgs) { }
-
- ///
- /// Check representing whether or not the door can be pried open.
- ///
- /// The eventArgs of the InteractUsing method that called this function.
- /// True if the door can be pried open, false if it cannot.
- bool CanPryCheck(InteractUsingEventArgs eventArgs) => true;
-
- }
-}
diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs
new file mode 100644
index 0000000000..73d6508272
--- /dev/null
+++ b/Content.Server/Doors/Systems/AirlockSystem.cs
@@ -0,0 +1,109 @@
+using Content.Server.Doors.Components;
+using Content.Server.Power.Components;
+using Content.Shared.Doors;
+using Content.Shared.Notification.Managers;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+
+namespace Content.Server.Doors.Systems
+{
+ public class AirlockSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPowerChanged);
+ SubscribeLocalEvent(OnStateChanged);
+ SubscribeLocalEvent(OnBeforeDoorOpened);
+ SubscribeLocalEvent(OnBeforeDoorClosed);
+ SubscribeLocalEvent(OnBeforeDoorDenied);
+ SubscribeLocalEvent(OnDoorSafetyCheck);
+ SubscribeLocalEvent(OnDoorAutoCloseCheck);
+ SubscribeLocalEvent(OnDoorCloseTimeModifier);
+ SubscribeLocalEvent(OnDoorClickShouldActivate);
+ SubscribeLocalEvent(OnDoorPry);
+ }
+
+ private void OnPowerChanged(EntityUid uid, AirlockComponent component, PowerChangedEvent args)
+ {
+ if (component.AppearanceComponent != null)
+ {
+ component.AppearanceComponent.SetData(DoorVisuals.Powered, args.Powered);
+ }
+
+ // BoltLights also got out
+ component.UpdateBoltLightStatus();
+ }
+
+ private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args)
+ {
+ // Only show the maintenance panel if the airlock is closed
+ if (component.WiresComponent != null)
+ {
+ component.WiresComponent.IsPanelVisible = args.State != SharedDoorComponent.DoorState.Open;
+ }
+ // If the door is closed, we should look if the bolt was locked while closing
+ component.UpdateBoltLightStatus();
+ }
+
+ private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args)
+ {
+ if (!component.CanChangeState())
+ args.Cancel();
+ }
+
+ private void OnBeforeDoorClosed(EntityUid uid, AirlockComponent component, BeforeDoorClosedEvent args)
+ {
+ if (!component.CanChangeState())
+ args.Cancel();
+ }
+
+ private void OnBeforeDoorDenied(EntityUid uid, AirlockComponent component, BeforeDoorDeniedEvent args)
+ {
+ if (!component.CanChangeState())
+ args.Cancel();
+ }
+
+ private void OnDoorSafetyCheck(EntityUid uid, AirlockComponent component, DoorSafetyEnabledEvent args)
+ {
+ args.Safety = component.Safety;
+ }
+
+ private void OnDoorAutoCloseCheck(EntityUid uid, AirlockComponent component, BeforeDoorAutoCloseEvent args)
+ {
+ if (!component.AutoClose)
+ args.Cancel();
+ }
+
+ private void OnDoorCloseTimeModifier(EntityUid uid, AirlockComponent component, DoorGetCloseTimeModifierEvent args)
+ {
+ args.CloseTimeModifier *= component.AutoCloseDelayModifier;
+ }
+
+ private void OnDoorClickShouldActivate(EntityUid uid, AirlockComponent component, DoorClickShouldActivateEvent args)
+ {
+ if (component.WiresComponent != null && component.WiresComponent.IsPanelOpen &&
+ args.Args.User.TryGetComponent(out ActorComponent? actor))
+ {
+ component.WiresComponent.OpenInterface(actor.PlayerSession);
+ args.Handled = true;
+ }
+ }
+
+ private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args)
+ {
+ if (component.IsBolted())
+ {
+ component.Owner.PopupMessage(args.Args.User, Loc.GetString("airlock-component-cannot-pry-is-bolted-message"));
+ args.Cancel();
+ }
+ if (component.IsPowered())
+ {
+ component.Owner.PopupMessage(args.Args.User, Loc.GetString("airlock-component-cannot-pry-is-powered-message"));
+ args.Cancel();
+ }
+ }
+ }
+}
diff --git a/Content.Server/Doors/DoorSystem.cs b/Content.Server/Doors/Systems/DoorSystem.cs
similarity index 100%
rename from Content.Server/Doors/DoorSystem.cs
rename to Content.Server/Doors/Systems/DoorSystem.cs
diff --git a/Content.Server/Doors/Systems/FirelockSystem.cs b/Content.Server/Doors/Systems/FirelockSystem.cs
new file mode 100644
index 0000000000..49ab584471
--- /dev/null
+++ b/Content.Server/Doors/Systems/FirelockSystem.cs
@@ -0,0 +1,69 @@
+using Content.Server.Doors.Components;
+using Content.Shared.Doors;
+using Content.Shared.Notification.Managers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+
+namespace Content.Server.Doors.Systems
+{
+ public class FirelockSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnBeforeDoorOpened);
+ SubscribeLocalEvent(OnBeforeDoorDenied);
+ SubscribeLocalEvent(OnDoorGetPryTimeModifier);
+ SubscribeLocalEvent(OnDoorClickShouldActivate);
+ SubscribeLocalEvent(OnBeforeDoorPry);
+ SubscribeLocalEvent(OnBeforeDoorAutoclose);
+ }
+
+ private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, BeforeDoorOpenedEvent args)
+ {
+ if (component.IsHoldingFire() || component.IsHoldingPressure())
+ args.Cancel();
+ }
+
+ private void OnBeforeDoorDenied(EntityUid uid, FirelockComponent component, BeforeDoorDeniedEvent args)
+ {
+ args.Cancel();
+ }
+
+ private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, DoorGetPryTimeModifierEvent args)
+ {
+ if (component.IsHoldingFire() || component.IsHoldingPressure())
+ args.PryTimeModifier *= component.LockedPryTimeModifier;
+ }
+
+ private void OnDoorClickShouldActivate(EntityUid uid, FirelockComponent component, DoorClickShouldActivateEvent args)
+ {
+ // We're a firelock, you can't click to open it
+ args.Handled = true;
+ }
+
+ private void OnBeforeDoorPry(EntityUid uid, FirelockComponent component, BeforeDoorPryEvent args)
+ {
+ if (component.DoorComponent == null || component.DoorComponent.State != SharedDoorComponent.DoorState.Closed)
+ {
+ return;
+ }
+
+ if (component.IsHoldingPressure())
+ {
+ component.Owner.PopupMessage(args.Args.User, Loc.GetString("firelock-component-is-holding-pressure-message"));
+ }
+ else if (component.IsHoldingFire())
+ {
+ component.Owner.PopupMessage(args.Args.User, Loc.GetString("firelock-component-is-holding-fire-message"));
+ }
+ }
+
+ private void OnBeforeDoorAutoclose(EntityUid uid, FirelockComponent component, BeforeDoorAutoCloseEvent args)
+ {
+ // Firelocks can't autoclose, they must be manually closed
+ args.Cancel();
+ }
+ }
+}
diff --git a/Content.Shared/Doors/SharedDoorComponent.cs b/Content.Shared/Doors/SharedDoorComponent.cs
index db6902c5c6..e85da53ff9 100644
--- a/Content.Shared/Doors/SharedDoorComponent.cs
+++ b/Content.Shared/Doors/SharedDoorComponent.cs
@@ -22,6 +22,9 @@ namespace Content.Shared.Doors
[ComponentDependency]
protected readonly IPhysBody? PhysicsComponent = null;
+ [Dependency]
+ protected readonly IGameTiming _gameTiming = default!;
+
[ViewVariables]
private DoorState _state = DoorState.Closed;
///
diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml
index 7b88ff7002..c570660647 100644
--- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml
+++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml
@@ -38,13 +38,16 @@
- SmallImpassable
- type: Door
board: DoorElectronics
+ openSound:
+ path: /Audio/Machines/airlock_open.ogg
+ closeSound:
+ path: /Audio/Machines/airlock_close.ogg
+ denySound:
+ path: /Audio/Machines/airlock_deny.ogg
- type: Airlock
- type: Appearance
visuals:
- type: AirlockVisualizer
- open_sound: /Audio/Machines/airlock_open.ogg
- close_sound: /Audio/Machines/airlock_close.ogg
- deny_sound: /Audio/Machines/airlock_deny.ogg
- type: WiresVisualizer
- type: ApcPowerReceiver
- type: Wires
diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml
index b33fa434c7..931987b355 100644
--- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml
+++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml
@@ -6,12 +6,15 @@
components:
- type: Door
bumpOpen: false
+ openSound:
+ path: /Audio/Machines/airlock_ext_open.ogg
+ closeSound:
+ path: /Audio/Machines/airlock_ext_close.ogg
+ denySound:
+ path: /Audio/Machines/airlock_deny.ogg
- type: Sprite
sprite: Structures/Doors/Airlocks/Standard/external.rsi
- type: Appearance
visuals:
- type: AirlockVisualizer
- open_sound: /Audio/Machines/airlock_ext_open.ogg
- close_sound: /Audio/Machines/airlock_ext_close.ogg
- deny_sound: /Audio/Machines/airlock_deny.ogg
- type: WiresVisualizer
diff --git a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml
index 40fad456b0..74cc60c768 100644
--- a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml
+++ b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml
@@ -54,13 +54,16 @@
startOpen: true
bumpOpen: false
inhibitCrush: false
+ openSound:
+ path: /Audio/Machines/airlock_open.ogg
+ closeSound:
+ path: /Audio/Machines/airlock_close.ogg
+ denySound:
+ path: /Audio/Machines/airlock_deny.ogg
- type: Firelock
- type: Appearance
visuals:
- type: AirlockVisualizer
- open_sound: /Audio/Machines/airlock_open.ogg
- close_sound: /Audio/Machines/airlock_close.ogg
- deny_sound: /Audio/Machines/airlock_deny.ogg
animation_time: 0.6
- type: WiresVisualizer
- type: Wires