Refactor IDoorCheck into entity events (#4366)

* IDoorCheck refactored to events

# Conflicts:
#	Content.Server/Atmos/TileAtmosphere.cs
#	Content.Server/Doors/Components/AirlockComponent.cs
#	Content.Server/Doors/Components/FirelockComponent.cs
#	Content.Server/Doors/Components/ServerDoorComponent.cs
#	Content.Server/Doors/IDoorCheck.cs

* namespaces

* Fix mapinit bug with refreshautoclose

* ok i guess these just didnt feel like staging today
This commit is contained in:
mirrorcult
2021-08-02 04:57:06 -07:00
committed by GitHub
parent 7e3d5f6cf1
commit af2e21c355
14 changed files with 545 additions and 338 deletions

View File

@@ -17,15 +17,6 @@ namespace Content.Client.Doors
{ {
private const string AnimationKey = "airlock_animation"; 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")] [DataField("animation_time")]
private float _delay = 0.8f; private float _delay = 0.8f;
@@ -51,14 +42,6 @@ namespace Content.Client.Doors
CloseAnimation.AnimationTracks.Add(flickMaintenancePanel); CloseAnimation.AnimationTracks.Add(flickMaintenancePanel);
flickMaintenancePanel.LayerKey = WiresVisualizer.WiresVisualLayers.MaintenancePanel; flickMaintenancePanel.LayerKey = WiresVisualizer.WiresVisualLayers.MaintenancePanel;
flickMaintenancePanel.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("panel_closing", 0f)); 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)}; OpenAnimation = new Animation {Length = TimeSpan.FromSeconds(_delay)};
@@ -80,11 +63,6 @@ namespace Content.Client.Doors
var sound = new AnimationTrackPlaySound(); var sound = new AnimationTrackPlaySound();
OpenAnimation.AnimationTracks.Add(sound); OpenAnimation.AnimationTracks.Add(sound);
if (_openSound != null)
{
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(_openSound, 0));
}
} }
DenyAnimation = new Animation {Length = TimeSpan.FromSeconds(0.3f)}; DenyAnimation = new Animation {Length = TimeSpan.FromSeconds(0.3f)};
@@ -96,11 +74,6 @@ namespace Content.Client.Doors
var sound = new AnimationTrackPlaySound(); var sound = new AnimationTrackPlaySound();
DenyAnimation.AnimationTracks.Add(sound); DenyAnimation.AnimationTracks.Add(sound);
if (_denySound != null)
{
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(_denySound, 0, () => AudioHelpers.WithVariation(0.05f)));
}
} }
} }

View File

@@ -5,6 +5,7 @@ using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Server.Coordinates.Helpers; using Content.Server.Coordinates.Helpers;
using Content.Server.Doors.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;

View File

@@ -7,12 +7,14 @@ using Content.Shared.Doors;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Notification; using Content.Shared.Notification;
using Content.Shared.Notification.Managers; using Content.Shared.Notification.Managers;
using Content.Shared.Sound;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using static Content.Shared.Wires.SharedWiresComponent; using static Content.Shared.Wires.SharedWiresComponent;
using static Content.Shared.Wires.SharedWiresComponent.WiresAction; 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. /// Companion component to ServerDoorComponent that handles airlock-specific behavior -- wires, requiring power to operate, bolts, and allowing automatic closing.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IDoorCheck))] public class AirlockComponent : Component, IWires
public class AirlockComponent : Component, IWires, IDoorCheck
{ {
public override string Name => "Airlock"; public override string Name => "Airlock";
[ComponentDependency] [ComponentDependency]
private readonly ServerDoorComponent? _doorComponent = null; public readonly ServerDoorComponent? DoorComponent = null;
[ComponentDependency] [ComponentDependency]
private readonly SharedAppearanceComponent? _appearanceComponent = null; public readonly SharedAppearanceComponent? AppearanceComponent = null;
[ComponentDependency] [ComponentDependency]
private readonly ApcPowerReceiverComponent? _receiverComponent = null; public readonly ApcPowerReceiverComponent? ReceiverComponent = null;
[ComponentDependency] [ComponentDependency]
private readonly WiresComponent? _wiresComponent = null; public readonly WiresComponent? WiresComponent = null;
/// <summary>
/// Sound to play when the bolts on the airlock go up.
/// </summary>
[DataField("boltUpSound")]
public SoundSpecifier BoltUpSound = new SoundPathSpecifier("/Audio/Machines/boltsup.ogg");
/// <summary>
/// Sound to play when the bolts on the airlock go down.
/// </summary>
[DataField("boltDownSound")]
public SoundSpecifier BoltDownSound = new SoundPathSpecifier("/Audio/Machines/boltsdown.ogg");
/// <summary> /// <summary>
/// Duration for which power will be disabled after pulsing either power wire. /// Duration for which power will be disabled after pulsing either power wire.
/// </summary> /// </summary>
private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0); [DataField("powerWiresTimeout")]
public float PowerWiresTimeout = 5.0f;
private CancellationTokenSource _powerWiresPulsedTimerCancel = new(); private CancellationTokenSource _powerWiresPulsedTimerCancel = new();
private bool _powerWiresPulsed; private bool _powerWiresPulsed;
/// <summary> /// <summary>
@@ -83,7 +96,7 @@ namespace Content.Server.Doors.Components
private bool BoltLightsVisible private bool BoltLightsVisible
{ {
get => _boltLightsWirePulsed && BoltsDown && IsPowered() get => _boltLightsWirePulsed && BoltsDown && IsPowered()
&& _doorComponent != null && _doorComponent.State == SharedDoorComponent.DoorState.Closed; && DoorComponent != null && DoorComponent.State == SharedDoorComponent.DoorState.Closed;
set set
{ {
_boltLightsWirePulsed = value; _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)] [ViewVariables(VVAccess.ReadWrite)]
private bool _autoClose = true; [DataField("autoCloseDelayModifier")]
public float AutoCloseDelayModifier = 1.0f;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
private bool _normalCloseSpeed = true; public bool Safety = true;
[ViewVariables(VVAccess.ReadWrite)]
private bool _safety = true;
protected override void Initialize() protected override void Initialize()
{ {
base.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) public bool CanChangeState()
{
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()
{ {
return IsPowered() && !IsBolted(); return IsPowered() && !IsBolted();
} }
private bool IsBolted() public bool IsBolted()
{ {
return _boltsDown; 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; return;
} }
@@ -214,9 +160,9 @@ namespace Content.Server.Doors.Components
{ {
powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR"); powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR");
} }
else if (_wiresComponent != null && else if (WiresComponent != null &&
_wiresComponent.IsWireCut(Wires.MainPower) && WiresComponent.IsWireCut(Wires.MainPower) &&
_wiresComponent.IsWireCut(Wires.BackupPower)) WiresComponent.IsWireCut(Wires.BackupPower))
{ {
powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR"); powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR");
} }
@@ -226,63 +172,59 @@ namespace Content.Server.Doors.Components
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 ev = new DoorGetCloseTimeModifierEvent();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
var timingStatus = var timingStatus =
new StatusLightData(Color.Orange, !_autoClose ? StatusLightState.Off : new StatusLightData(Color.Orange, !AutoClose ? StatusLightState.Off :
!_normalCloseSpeed ? StatusLightState.BlinkingSlow : !MathHelper.CloseTo(ev.CloseTimeModifier, 1.0f) ? StatusLightState.BlinkingSlow :
StatusLightState.On, StatusLightState.On,
"TIME"); "TIME");
var safetyStatus = 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; return;
} }
_wiresComponent.SetStatus(AirlockWireStatus.PowerIndicator, powerLight); WiresComponent.SetStatus(AirlockWireStatus.PowerIndicator, powerLight);
_wiresComponent.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus); WiresComponent.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
_wiresComponent.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus); WiresComponent.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
_wiresComponent.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT")); WiresComponent.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
_wiresComponent.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus); WiresComponent.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
_wiresComponent.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus); 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);*/
} }
private void UpdatePowerCutStatus() private void UpdatePowerCutStatus()
{ {
if (_receiverComponent == null) if (ReceiverComponent == null)
{ {
return; return;
} }
if (PowerWiresPulsed) if (PowerWiresPulsed)
{ {
_receiverComponent.PowerDisabled = true; ReceiverComponent.PowerDisabled = true;
return; return;
} }
if (_wiresComponent == null) if (WiresComponent == null)
{ {
return; return;
} }
_receiverComponent.PowerDisabled = ReceiverComponent.PowerDisabled =
_wiresComponent.IsWireCut(Wires.MainPower) || WiresComponent.IsWireCut(Wires.MainPower) ||
_wiresComponent.IsWireCut(Wires.BackupPower); WiresComponent.IsWireCut(Wires.BackupPower);
} }
private void PowerDeviceOnOnPowerStateChanged(PowerChangedMessage e) 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 // BoltLights also got out
@@ -341,19 +283,13 @@ namespace Content.Server.Doors.Components
builder.CreateWire(Wires.BoltLight); builder.CreateWire(Wires.BoltLight);
builder.CreateWire(Wires.Timing); builder.CreateWire(Wires.Timing);
builder.CreateWire(Wires.Safety); builder.CreateWire(Wires.Safety);
/*
builder.CreateWire(6);
builder.CreateWire(7);
builder.CreateWire(8);
builder.CreateWire(9);
builder.CreateWire(10);
builder.CreateWire(11);*/
UpdateWiresStatus(); UpdateWiresStatus();
} }
public void WiresUpdate(WiresUpdateEventArgs args) public void WiresUpdate(WiresUpdateEventArgs args)
{ {
if(_doorComponent == null) if(DoorComponent == null)
{ {
return; return;
} }
@@ -367,7 +303,7 @@ namespace Content.Server.Doors.Components
PowerWiresPulsed = true; PowerWiresPulsed = true;
_powerWiresPulsedTimerCancel.Cancel(); _powerWiresPulsedTimerCancel.Cancel();
_powerWiresPulsedTimerCancel = new CancellationTokenSource(); _powerWiresPulsedTimerCancel = new CancellationTokenSource();
Owner.SpawnTimer(PowerWiresTimeout, Owner.SpawnTimer(TimeSpan.FromSeconds(PowerWiresTimeout),
() => PowerWiresPulsed = false, () => PowerWiresPulsed = false,
_powerWiresPulsedTimerCancel.Token); _powerWiresPulsedTimerCancel.Token);
break; break;
@@ -390,11 +326,11 @@ namespace Content.Server.Doors.Components
BoltLightsVisible = !_boltLightsWirePulsed; BoltLightsVisible = !_boltLightsWirePulsed;
break; break;
case Wires.Timing: case Wires.Timing:
_normalCloseSpeed = !_normalCloseSpeed; AutoCloseDelayModifier = 0.5f;
_doorComponent.RefreshAutoClose(); DoorComponent.RefreshAutoClose();
break; break;
case Wires.Safety: case Wires.Safety:
_safety = !_safety; Safety = !Safety;
break; break;
} }
} }
@@ -413,11 +349,11 @@ namespace Content.Server.Doors.Components
BoltLightsVisible = true; BoltLightsVisible = true;
break; break;
case Wires.Timing: case Wires.Timing:
_autoClose = true; AutoClose = true;
_doorComponent.RefreshAutoClose(); DoorComponent.RefreshAutoClose();
break; break;
case Wires.Safety: case Wires.Safety:
_safety = true; Safety = true;
break; break;
} }
} }
@@ -433,11 +369,11 @@ namespace Content.Server.Doors.Components
BoltLightsVisible = false; BoltLightsVisible = false;
break; break;
case Wires.Timing: case Wires.Timing:
_autoClose = false; AutoClose = false;
_doorComponent.RefreshAutoClose(); DoorComponent.RefreshAutoClose();
break; break;
case Wires.Safety: case Wires.Safety:
_safety = false; Safety = false;
break; break;
} }
} }
@@ -455,7 +391,7 @@ namespace Content.Server.Doors.Components
BoltsDown = newBolts; 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);
} }
} }
} }

View File

@@ -1,3 +1,4 @@
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.EntitySystems;
using Content.Server.Doors; using Content.Server.Doors;
using Content.Server.Doors.Components; using Content.Server.Doors.Components;
@@ -6,26 +7,34 @@ using Content.Shared.Interaction;
using Content.Shared.Notification.Managers; using Content.Shared.Notification.Managers;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Server.Atmos.Components namespace Content.Server.Doors.Components
{ {
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IDoorCheck))] public class FirelockComponent : Component
public class FirelockComponent : Component, IDoorCheck
{ {
public override string Name => "Firelock"; public override string Name => "Firelock";
[ComponentDependency] [ComponentDependency]
private readonly ServerDoorComponent? _doorComponent = null; public readonly ServerDoorComponent? DoorComponent = null;
/// <summary>
/// Pry time modifier to be used when the firelock is currently closed due to fire or pressure.
/// </summary>
/// <returns></returns>
[DataField("lockedPryTimeModifier")]
public float LockedPryTimeModifier = 1.5f;
public bool EmergencyPressureStop() 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)) if (Owner.TryGetComponent(out AirtightComponent? airtight))
{ {
EntitySystem.Get<AirtightSystem>().SetAirblocked(airtight, true); EntitySystem.Get<AirtightSystem>().SetAirblocked(airtight, true);
@@ -35,41 +44,6 @@ namespace Content.Server.Atmos.Components
return false; 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) public bool IsHoldingPressure(float threshold = 20)
{ {
var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>(); var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();

View File

@@ -14,6 +14,7 @@ using Content.Shared.Damage;
using Content.Shared.Damage.Components; using Content.Shared.Damage.Components;
using Content.Shared.Doors; using Content.Shared.Doors;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Sound;
using Content.Shared.Tool; using Content.Shared.Tool;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -37,9 +38,6 @@ namespace Content.Server.Doors.Components
[ComponentReference(typeof(SharedDoorComponent))] [ComponentReference(typeof(SharedDoorComponent))]
public class ServerDoorComponent : SharedDoorComponent, IActivate, IInteractUsing, IMapInit public class ServerDoorComponent : SharedDoorComponent, IActivate, IInteractUsing, IMapInit
{ {
[ComponentDependency]
private readonly IDoorCheck? _doorCheck = null;
[ViewVariables] [ViewVariables]
[DataField("board")] [DataField("board")]
private string? _boardPrototype; private string? _boardPrototype;
@@ -63,11 +61,8 @@ namespace Content.Server.Doors.Components
_ => throw new ArgumentOutOfRangeException(), _ => throw new ArgumentOutOfRangeException(),
}; };
if (_doorCheck != null) Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new DoorStateChangedEvent(State), false);
{ _autoCloseCancelTokenSource?.Cancel();
_doorCheck.OnStateChange(State);
RefreshAutoClose();
}
Dirty(); Dirty();
} }
@@ -105,7 +100,7 @@ namespace Content.Server.Doors.Components
/// Handled in Startup(). /// Handled in Startup().
/// </summary> /// </summary>
[ViewVariables(VVAccess.ReadWrite)] [DataField("startOpen")] [ViewVariables(VVAccess.ReadWrite)] [DataField("startOpen")]
private bool _startOpen; private bool _startOpen = false;
/// <summary> /// <summary>
/// Whether the airlock is welded shut. Can be set by the prototype, although this will fail if the door isn't weldable. /// 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")] [DataField("weldable")]
private bool _weldable = true; private bool _weldable = true;
/// <summary>
/// Sound to play when the door opens.
/// </summary>
[DataField("openSound")]
public SoundSpecifier? OpenSound;
/// <summary>
/// Sound to play when the door closes.
/// </summary>
[DataField("closeSound")]
public SoundSpecifier? CloseSound;
/// <summary>
/// Sound to play if the door is denied.
/// </summary>
[DataField("denySound")]
public SoundSpecifier? DenySound;
/// <summary>
/// Default time that the door should take to pry open.
/// </summary>
[DataField("pryTime")]
public float PryTime = 0.5f;
/// <summary>
/// Minimum interval allowed between deny sounds in milliseconds.
/// </summary>
[DataField("denySoundMinimumInterval")]
public float DenySoundMinimumInterval = 250.0f;
/// <summary>
/// Used to stop people from spamming the deny sound.
/// </summary>
private TimeSpan LastDenySoundTime = TimeSpan.Zero;
/// <summary> /// <summary>
/// Whether the door can currently be welded. /// Whether the door can currently be welded.
/// </summary> /// </summary>
@@ -149,6 +179,7 @@ namespace Content.Server.Doors.Components
/// </summary> /// </summary>
private bool _beingWelded; private bool _beingWelded;
//[ViewVariables(VVAccess.ReadWrite)] //[ViewVariables(VVAccess.ReadWrite)]
//[DataField("canCrush")] //[DataField("canCrush")]
//private bool _canCrush = true; // TODO implement door crushing //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); Logger.Warning("{0} prototype loaded with incompatible flags: 'welded' and 'startOpen' are both true.", Owner.Name);
return; return;
} }
QuickOpen(); QuickOpen(false);
} }
CreateDoorElectronicsBoard(); CreateDoorElectronicsBoard();
@@ -195,10 +226,10 @@ namespace Content.Server.Doors.Components
void IActivate.Activate(ActivateEventArgs eventArgs) 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; return;
}
if (State == DoorState.Open) if (State == DoorState.Open)
{ {
@@ -279,12 +310,10 @@ namespace Content.Server.Doors.Components
{ {
return false; 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;
} }
/// <summary> /// <summary>
@@ -301,12 +330,19 @@ namespace Content.Server.Doors.Components
_stateChangeCancelTokenSource?.Cancel(); _stateChangeCancelTokenSource?.Cancel();
_stateChangeCancelTokenSource = new(); _stateChangeCancelTokenSource = new();
if (OpenSound != null)
{
SoundSystem.Play(Filter.Pvs(Owner), OpenSound.GetSound(),
AudioParams.Default.WithVolume(-5));
}
Owner.SpawnTimer(OpenTimeOne, async () => Owner.SpawnTimer(OpenTimeOne, async () =>
{ {
OnPartialOpen(); OnPartialOpen();
await Timer.Delay(OpenTimeTwo, _stateChangeCancelTokenSource.Token); await Timer.Delay(OpenTimeTwo, _stateChangeCancelTokenSource.Token);
State = DoorState.Open; State = DoorState.Open;
RefreshAutoClose();
}, _stateChangeCancelTokenSource.Token); }, _stateChangeCancelTokenSource.Token);
} }
@@ -320,7 +356,7 @@ namespace Content.Server.Doors.Components
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner, false)); 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)) if (Occludes && Owner.TryGetComponent(out OccluderComponent? occluder))
{ {
@@ -328,6 +364,8 @@ namespace Content.Server.Doors.Components
} }
OnPartialOpen(); OnPartialOpen();
State = DoorState.Open; State = DoorState.Open;
if(refresh)
RefreshAutoClose();
} }
#endregion #endregion
@@ -366,17 +404,19 @@ namespace Content.Server.Doors.Components
/// <returns>Boolean describing whether this door can close.</returns> /// <returns>Boolean describing whether this door can close.</returns>
public bool CanCloseGeneric() 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 false;
}
return !IsSafetyColliding(); return !IsSafetyColliding();
} }
private bool SafetyCheck() 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;
} }
/// <summary> /// <summary>
@@ -412,6 +452,13 @@ namespace Content.Server.Doors.Components
_stateChangeCancelTokenSource?.Cancel(); _stateChangeCancelTokenSource?.Cancel();
_stateChangeCancelTokenSource = new(); _stateChangeCancelTokenSource = new();
if (CloseSound != null)
{
SoundSystem.Play(Filter.Pvs(Owner), CloseSound.GetSound(),
AudioParams.Default.WithVolume(-10));
}
Owner.SpawnTimer(CloseTimeOne, async () => Owner.SpawnTimer(CloseTimeOne, async () =>
{ {
// if somebody walked into the door as it was closing, and we don't crush things // 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() public void Deny()
{ {
if (_doorCheck != null && !_doorCheck.DenyCheck()) var ev = new BeforeDoorDeniedEvent();
{ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
if (ev.Cancelled)
return; return;
}
if (State == DoorState.Open || IsWeldedShut) if (State == DoorState.Open || IsWeldedShut)
return; return;
@@ -515,6 +562,25 @@ namespace Content.Server.Doors.Components
_stateChangeCancelTokenSource?.Cancel(); _stateChangeCancelTokenSource?.Cancel();
_stateChangeCancelTokenSource = new(); _stateChangeCancelTokenSource = new();
SetAppearance(DoorVisualState.Deny); 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, () => Owner.SpawnTimer(DenyTime, () =>
{ {
SetAppearance(DoorVisualState.Closed); SetAppearance(DoorVisualState.Closed);
@@ -522,19 +588,24 @@ namespace Content.Server.Doors.Components
} }
/// <summary> /// <summary>
/// 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).
/// </summary> /// </summary>
public void RefreshAutoClose() public void RefreshAutoClose()
{ {
_autoCloseCancelTokenSource?.Cancel(); if (State != DoorState.Open)
if (State != DoorState.Open || _doorCheck == null || !_doorCheck.AutoCloseCheck())
{
return; return;
}
var autoev = new BeforeDoorAutoCloseEvent();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, autoev, false);
if (autoev.Cancelled)
return;
_autoCloseCancelTokenSource = new(); _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 () => Owner.SpawnRepeatingTimer(realCloseTime, async () =>
{ {
@@ -556,21 +627,18 @@ namespace Content.Server.Doors.Components
// for prying doors // for prying doors
if (tool.HasQuality(ToolQuality.Prying) && !IsWeldedShut) if (tool.HasQuality(ToolQuality.Prying) && !IsWeldedShut)
{ {
var successfulPry = false; var ev = new DoorGetPryTimeModifierEvent();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ev, false);
if (_doorCheck != null) var canEv = new BeforeDoorPryEvent(eventArgs);
{ Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, canEv, false);
_doorCheck.OnStartPry(eventArgs);
successfulPry = await tool.UseTool(eventArgs.User, Owner, var successfulPry = await tool.UseTool(eventArgs.User, Owner,
_doorCheck.GetPryTime() ?? 0.5f, ToolQuality.Prying, () => _doorCheck.CanPryCheck(eventArgs)); ev.PryTimeModifier * PryTime, ToolQuality.Prying, () => !canEv.Cancelled);
}
else
{
successfulPry = await tool.UseTool(eventArgs.User, Owner, 0.5f, ToolQuality.Prying);
}
if (successfulPry && !IsWeldedShut) if (successfulPry && !IsWeldedShut)
{ {
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new OnDoorPryEvent(eventArgs), false);
if (State == DoorState.Closed) if (State == DoorState.Closed)
{ {
Open(); Open();

View File

@@ -0,0 +1,141 @@
#nullable enable
using System;
using Content.Shared.Doors;
using Content.Shared.Interaction;
using Robust.Shared.GameObjects;
namespace Content.Server.Doors
{
/// <summary>
/// Raised when the door's State variable is changed to a new variable that it was not equal to before.
/// </summary>
public class DoorStateChangedEvent : EntityEventArgs
{
public SharedDoorComponent.DoorState State;
public DoorStateChangedEvent(SharedDoorComponent.DoorState state)
{
State = state;
}
}
/// <summary>
/// Raised when the door is determining whether it is able to open.
/// Cancel to stop the door from being opened.
/// </summary>
public class BeforeDoorOpenedEvent : CancellableEntityEventArgs
{
}
/// <summary>
/// Raised when the door is successfully opened.
/// </summary>
public class OnDoorOpenedEvent : HandledEntityEventArgs
{
}
/// <summary>
/// Raised when the door is determining whether it is able to close.
/// Cancel to stop the door from being closed.
/// </summary>
public class BeforeDoorClosedEvent : CancellableEntityEventArgs
{
}
/// <summary>
/// Raised when the door is successfully closed.
/// </summary>
public class OnDoorClosedEvent : HandledEntityEventArgs
{
}
/// <summary>
/// Called when the door is determining whether it is able to deny.
/// Cancel to stop the door from being able to deny.
/// </summary>
public class BeforeDoorDeniedEvent : CancellableEntityEventArgs
{
}
/// <summary>
/// Raised when access to the door is denied.
/// </summary>
public class OnDoorDeniedEvent : HandledEntityEventArgs
{
}
/// <summary>
/// Raised to determine whether the door's safety is on.
/// Modify Safety to set the door's safety.
/// </summary>
public class DoorSafetyEnabledEvent : HandledEntityEventArgs
{
public bool Safety = false;
}
/// <summary>
/// Raised to determine whether the door should automatically close.
/// Cancel to stop it from automatically closing.
/// </summary>
public class BeforeDoorAutoCloseEvent : CancellableEntityEventArgs
{
}
/// <summary>
/// Raised to determine how long the door's pry time should be modified by.
/// Multiply PryTimeModifier by the desired amount.
/// </summary>
public class DoorGetPryTimeModifierEvent : EntityEventArgs
{
public float PryTimeModifier = 1.0f;
}
/// <summary>
/// Raised to determine how long the door's close time should be modified by.
/// Multiply CloseTimeModifier by the desired amount.
/// </summary>
public class DoorGetCloseTimeModifierEvent : EntityEventArgs
{
public float CloseTimeModifier = 1.0f;
}
/// <summary>
/// Raised to determine whether clicking the door should open/close it.
/// </summary>
public class DoorClickShouldActivateEvent : HandledEntityEventArgs
{
public ActivateEventArgs Args;
public DoorClickShouldActivateEvent(ActivateEventArgs args)
{
Args = args;
}
}
/// <summary>
/// Raised when an attempt to pry open the door is made.
/// Cancel to stop the door from being pried open.
/// </summary>
public class BeforeDoorPryEvent : CancellableEntityEventArgs
{
public InteractUsingEventArgs Args;
public BeforeDoorPryEvent(InteractUsingEventArgs args)
{
Args = args;
}
}
/// <summary>
/// Raised when a door is successfully pried open.
/// </summary>
public class OnDoorPryEvent : EntityEventArgs
{
public InteractUsingEventArgs Args;
public OnDoorPryEvent(InteractUsingEventArgs args)
{
Args = args;
}
}
}

View File

@@ -1,76 +0,0 @@
using System;
using Content.Shared.Doors;
using Content.Shared.Interaction;
namespace Content.Server.Doors
{
public interface IDoorCheck
{
/// <summary>
/// Called when the door's State variable is changed to a new variable that it was not equal to before.
/// </summary>
void OnStateChange(SharedDoorComponent.DoorState doorState) { }
/// <summary>
/// Called when the door is determining whether it is able to open.
/// </summary>
/// <returns>True if the door should open, false if it should not.</returns>
bool OpenCheck() => true;
/// <summary>
/// Called when the door is determining whether it is able to close.
/// </summary>
/// <returns>True if the door should close, false if it should not.</returns>
bool CloseCheck() => true;
/// <summary>
/// Called when the door is determining whether it is able to deny.
/// </summary>
/// <returns>True if the door should deny, false if it should not.</returns>
bool DenyCheck() => true;
/// <summary>
/// Whether the door's safety is on.
/// </summary>
/// <returns>True if safety is on, false if it is not.</returns>
bool SafetyCheck() => false;
/// <summary>
/// Whether the door should close automatically.
/// </summary>
/// <returns>True if the door should close automatically, false if it should not.</returns>
bool AutoCloseCheck() => false;
/// <summary>
/// Gets an override for the amount of time to pry open the door, or null if there is no override.
/// </summary>
/// <returns>Float if there is an override, null otherwise.</returns>
float? GetPryTime() => null;
/// <summary>
/// Gets an override for the amount of time before the door automatically closes, or null if there is no override.
/// </summary>
/// <returns>TimeSpan if there is an override, null otherwise.</returns>
TimeSpan? GetCloseSpeed() => null;
/// <summary>
/// A check to determine whether or not a click on the door should interact with it with the intent to open/close.
/// </summary>
/// <returns>True if the door's IActivate should not run, false otherwise.</returns>
bool BlockActivate(ActivateEventArgs eventArgs) => false;
/// <summary>
/// Called when somebody begins to pry open the door.
/// </summary>
/// <param name="eventArgs">The eventArgs of the InteractUsing method that called this function.</param>
void OnStartPry(InteractUsingEventArgs eventArgs) { }
/// <summary>
/// Check representing whether or not the door can be pried open.
/// </summary>
/// <param name="eventArgs">The eventArgs of the InteractUsing method that called this function.</param>
/// <returns>True if the door can be pried open, false if it cannot.</returns>
bool CanPryCheck(InteractUsingEventArgs eventArgs) => true;
}
}

View File

@@ -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<AirlockComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<AirlockComponent, DoorStateChangedEvent>(OnStateChanged);
SubscribeLocalEvent<AirlockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<AirlockComponent, BeforeDoorClosedEvent>(OnBeforeDoorClosed);
SubscribeLocalEvent<AirlockComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
SubscribeLocalEvent<AirlockComponent, DoorSafetyEnabledEvent>(OnDoorSafetyCheck);
SubscribeLocalEvent<AirlockComponent, BeforeDoorAutoCloseEvent>(OnDoorAutoCloseCheck);
SubscribeLocalEvent<AirlockComponent, DoorGetCloseTimeModifierEvent>(OnDoorCloseTimeModifier);
SubscribeLocalEvent<AirlockComponent, DoorClickShouldActivateEvent>(OnDoorClickShouldActivate);
SubscribeLocalEvent<AirlockComponent, BeforeDoorPryEvent>(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();
}
}
}
}

View File

@@ -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<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<FirelockComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
SubscribeLocalEvent<FirelockComponent, DoorGetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
SubscribeLocalEvent<FirelockComponent, DoorClickShouldActivateEvent>(OnDoorClickShouldActivate);
SubscribeLocalEvent<FirelockComponent, BeforeDoorPryEvent>(OnBeforeDoorPry);
SubscribeLocalEvent<FirelockComponent, BeforeDoorAutoCloseEvent>(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();
}
}
}

View File

@@ -22,6 +22,9 @@ namespace Content.Shared.Doors
[ComponentDependency] [ComponentDependency]
protected readonly IPhysBody? PhysicsComponent = null; protected readonly IPhysBody? PhysicsComponent = null;
[Dependency]
protected readonly IGameTiming _gameTiming = default!;
[ViewVariables] [ViewVariables]
private DoorState _state = DoorState.Closed; private DoorState _state = DoorState.Closed;
/// <summary> /// <summary>

View File

@@ -38,13 +38,16 @@
- SmallImpassable - SmallImpassable
- type: Door - type: Door
board: DoorElectronics 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: Airlock
- type: Appearance - type: Appearance
visuals: visuals:
- type: AirlockVisualizer - 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: WiresVisualizer
- type: ApcPowerReceiver - type: ApcPowerReceiver
- type: Wires - type: Wires

View File

@@ -6,12 +6,15 @@
components: components:
- type: Door - type: Door
bumpOpen: false 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 - type: Sprite
sprite: Structures/Doors/Airlocks/Standard/external.rsi sprite: Structures/Doors/Airlocks/Standard/external.rsi
- type: Appearance - type: Appearance
visuals: visuals:
- type: AirlockVisualizer - 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 - type: WiresVisualizer

View File

@@ -54,13 +54,16 @@
startOpen: true startOpen: true
bumpOpen: false bumpOpen: false
inhibitCrush: 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: Firelock
- type: Appearance - type: Appearance
visuals: visuals:
- type: AirlockVisualizer - 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 animation_time: 0.6
- type: WiresVisualizer - type: WiresVisualizer
- type: Wires - type: Wires