diff --git a/Content.Client/Doors/AirlockSystem.cs b/Content.Client/Doors/AirlockSystem.cs index cf4c3dfca0..18b9eae5f3 100644 --- a/Content.Client/Doors/AirlockSystem.cs +++ b/Content.Client/Doors/AirlockSystem.cs @@ -86,7 +86,8 @@ public sealed class AirlockSystem : SharedAirlockSystem if (_appearanceSystem.TryGetData(uid, DoorVisuals.Powered, out var powered, args.Component) && powered) { - boltedVisible = _appearanceSystem.TryGetData(uid, DoorVisuals.BoltLights, out var lights, args.Component) && lights; + boltedVisible = _appearanceSystem.TryGetData(uid, DoorVisuals.BoltLights, out var lights, args.Component) + && lights && state == DoorState.Closed; emergencyLightsVisible = _appearanceSystem.TryGetData(uid, DoorVisuals.EmergencyLights, out var eaLights, args.Component) && eaLights; unlitVisible = state == DoorState.Closing diff --git a/Content.Client/Doors/DoorBoltSystem.cs b/Content.Client/Doors/DoorBoltSystem.cs new file mode 100644 index 0000000000..58144cd6e0 --- /dev/null +++ b/Content.Client/Doors/DoorBoltSystem.cs @@ -0,0 +1,12 @@ +using Content.Client.Wires.Visualizers; +using Content.Shared.Doors.Components; +using Content.Shared.Doors.Systems; +using Robust.Client.Animations; +using Robust.Client.GameObjects; + +namespace Content.Client.Doors; + +public sealed class DoorBoltSystem : SharedDoorBoltSystem +{ + // Instantiate sub-class on client for prediction. +} diff --git a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs index e168ee8beb..b61eaf4621 100644 --- a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs +++ b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs @@ -38,6 +38,7 @@ namespace Content.IntegrationTests.Tests.Doors components: - type: Door - type: Airlock + - type: DoorBolt - type: ApcPowerReceiver needsPower: false - type: Physics diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs index 8e320f2bc0..e948f0b47e 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs @@ -39,6 +39,7 @@ namespace Content.Server.Administration.Systems; public sealed partial class AdminVerbSystem { + [Dependency] private readonly DoorBoltSystem _boltsSystem = default!; [Dependency] private readonly AirlockSystem _airlockSystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!; [Dependency] private readonly SharedAccessSystem _accessSystem = default!; @@ -60,28 +61,31 @@ public sealed partial class AdminVerbSystem if (_adminManager.HasAdminFlag(player, AdminFlags.Admin)) { - if (TryComp(args.Target, out var airlock)) + if (TryComp(args.Target, out var bolts)) { Verb bolt = new() { - Text = airlock.BoltsDown ? "Unbolt" : "Bolt", + Text = bolts.BoltsDown ? "Unbolt" : "Bolt", Category = VerbCategory.Tricks, - Icon = airlock.BoltsDown - ? new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/unbolt.png")) - : new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/bolt.png")), + Icon = bolts.BoltsDown + ? new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/unbolt.png")) + : new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bolt.png")), Act = () => { - _airlockSystem.SetBoltsWithAudio(args.Target, airlock, !airlock.BoltsDown); + _boltsSystem.SetBoltsWithAudio(args.Target, bolts, !bolts.BoltsDown); }, Impact = LogImpact.Medium, - Message = Loc.GetString(airlock.BoltsDown + Message = Loc.GetString(bolts.BoltsDown ? "admin-trick-unbolt-description" : "admin-trick-bolt-description"), - Priority = (int) (airlock.BoltsDown ? TricksVerbPriorities.Unbolt : TricksVerbPriorities.Bolt), + Priority = (int) (bolts.BoltsDown ? TricksVerbPriorities.Unbolt : TricksVerbPriorities.Bolt), }; args.Verbs.Add(bolt); + } + if (TryComp(args.Target, out var airlock)) + { Verb emergencyAccess = new() { Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On", diff --git a/Content.Server/Construction/Conditions/AirlockBolted.cs b/Content.Server/Construction/Conditions/AirlockBolted.cs index 06a60118b9..6f1b98ae0b 100644 --- a/Content.Server/Construction/Conditions/AirlockBolted.cs +++ b/Content.Server/Construction/Conditions/AirlockBolted.cs @@ -7,14 +7,14 @@ namespace Content.Server.Construction.Conditions { [UsedImplicitly] [DataDefinition] - public sealed class AirlockBolted : IGraphCondition + public sealed class DoorBolted : IGraphCondition { [DataField("value")] public bool Value { get; private set; } = true; public bool Condition(EntityUid uid, IEntityManager entityManager) { - if (!entityManager.TryGetComponent(uid, out AirlockComponent? airlock)) + if (!entityManager.TryGetComponent(uid, out DoorBoltComponent? airlock)) return true; return airlock.BoltsDown == Value; @@ -26,7 +26,7 @@ namespace Content.Server.Construction.Conditions var entMan = IoCManager.Resolve(); - if (!entMan.TryGetComponent(entity, out AirlockComponent? airlock)) return false; + if (!entMan.TryGetComponent(entity, out DoorBoltComponent? airlock)) return false; if (airlock.BoltsDown != Value) { diff --git a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs index be8babd862..54b5c36f35 100644 --- a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs @@ -11,7 +11,7 @@ namespace Content.Server.DeviceLinking.Systems [UsedImplicitly] public sealed class DoorSignalControlSystem : EntitySystem { - [Dependency] private readonly AirlockSystem _airlockSystem = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; @@ -67,18 +67,18 @@ namespace Content.Server.DeviceLinking.Systems { if (state == SignalState.High) { - if(TryComp(uid, out var airlockComponent)) - _airlockSystem.SetBoltsWithAudio(uid, airlockComponent, true); + if(TryComp(uid, out var bolts)) + _bolts.SetBoltsWithAudio(uid, bolts, true); } else if (state == SignalState.Momentary) { - if (TryComp(uid, out var airlockComponent)) - _airlockSystem.SetBoltsWithAudio(uid, airlockComponent, newBolts: !airlockComponent.BoltsDown); + if (TryComp(uid, out var bolts)) + _bolts.SetBoltsWithAudio(uid, bolts, newBolts: !bolts.BoltsDown); } else { - if(TryComp(uid, out var airlockComponent)) - _airlockSystem.SetBoltsWithAudio(uid, airlockComponent, false); + if(TryComp(uid, out var bolts)) + _bolts.SetBoltsWithAudio(uid, bolts, false); } } } diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs index 5eed14fc2f..939ee10c6e 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -18,6 +18,7 @@ namespace Content.Server.Doors.Systems [Dependency] private readonly WiresSystem _wiresSystem = default!; [Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly SignalLinkerSystem _signalSystem = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; public override void Initialize() { @@ -70,14 +71,8 @@ namespace Content.Server.Doors.Systems } else { - if (component.BoltWireCut) - SetBoltsWithAudio(uid, component, true); - UpdateAutoClose(uid, door: door); } - - // BoltLights also got out - UpdateBoltLightStatus(uid, component); } private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) @@ -91,7 +86,6 @@ namespace Content.Server.Doors.Systems _wiresSystem.ChangePanelVisibility(uid, wiresPanel, component.OpenPanelVisible || args.State != DoorState.Open); } // If the door is closed, we should look if the bolt was locked while closing - UpdateBoltLightStatus(uid, component); UpdateAutoClose(uid, component); // Make sure the airlock auto closes again next time it is opened @@ -180,12 +174,6 @@ namespace Content.Server.Doors.Systems private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args) { - if (component.BoltsDown) - { - Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User); - args.Cancel(); - } - if (this.IsPowered(uid, EntityManager)) { if (HasComp(args.Tool)) @@ -197,52 +185,7 @@ namespace Content.Server.Doors.Systems public bool CanChangeState(EntityUid uid, AirlockComponent component) { - return this.IsPowered(uid, EntityManager) && !component.BoltsDown; - } - - public void UpdateBoltLightStatus(EntityUid uid, AirlockComponent component) - { - if (!TryComp(uid, out var appearance)) - return; - - Appearance.SetData(uid, DoorVisuals.BoltLights, GetBoltLightsVisible(uid, component), appearance); - } - - public void SetBoltsWithAudio(EntityUid uid, AirlockComponent component, bool newBolts) - { - if (newBolts == component.BoltsDown) - return; - - component.BoltsDown = newBolts; - Audio.PlayPvs(newBolts ? component.BoltDownSound : component.BoltUpSound, uid); - UpdateBoltLightStatus(uid, component); - } - - public bool GetBoltLightsVisible(EntityUid uid, AirlockComponent component) - { - return component.BoltLightsEnabled && - component.BoltsDown && - this.IsPowered(uid, EntityManager) && - TryComp(uid, out var doorComponent) && - doorComponent.State == DoorState.Closed; - } - - public void SetBoltLightsEnabled(EntityUid uid, AirlockComponent component, bool value) - { - if (component.BoltLightsEnabled == value) - return; - - component.BoltLightsEnabled = value; - UpdateBoltLightStatus(uid, component); - } - - public void SetBoltsDown(EntityUid uid, AirlockComponent component, bool value) - { - if (component.BoltsDown == value) - return; - - component.BoltsDown = value; - UpdateBoltLightStatus(uid, component); + return this.IsPowered(uid, EntityManager) && !_bolts.IsBolted(uid); } } } diff --git a/Content.Server/Doors/Systems/DoorBoltSystem.cs b/Content.Server/Doors/Systems/DoorBoltSystem.cs new file mode 100644 index 0000000000..133af0013d --- /dev/null +++ b/Content.Server/Doors/Systems/DoorBoltSystem.cs @@ -0,0 +1,90 @@ +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Shared.Doors; +using Content.Shared.Doors.Components; +using Content.Shared.Doors.Systems; + +namespace Content.Server.Doors.Systems; + +public sealed class DoorBoltSystem : SharedDoorBoltSystem +{ + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnStateChanged); + } + + private void OnPowerChanged(EntityUid uid, DoorBoltComponent component, ref PowerChangedEvent args) + { + if (args.Powered) + { + if (component.BoltWireCut) + SetBoltsWithAudio(uid, component, true); + } + + UpdateBoltLightStatus(uid, component); + } + + public void UpdateBoltLightStatus(EntityUid uid, DoorBoltComponent component) + { + if (!TryComp(uid, out var appearance)) + return; + + Appearance.SetData(uid, DoorVisuals.BoltLights, GetBoltLightsVisible(uid, component), appearance); + } + + public bool GetBoltLightsVisible(EntityUid uid, DoorBoltComponent component) + { + return component.BoltLightsEnabled && + component.BoltsDown && + this.IsPowered(uid, EntityManager); + } + + public void SetBoltLightsEnabled(EntityUid uid, DoorBoltComponent component, bool value) + { + if (component.BoltLightsEnabled == value) + return; + + component.BoltLightsEnabled = value; + UpdateBoltLightStatus(uid, component); + } + + public void SetBoltsDown(EntityUid uid, DoorBoltComponent component, bool value) + { + if (component.BoltsDown == value) + return; + + component.BoltsDown = value; + UpdateBoltLightStatus(uid, component); + } + + private void OnStateChanged(EntityUid uid, DoorBoltComponent component, DoorStateChangedEvent args) + { + // If the door is closed, we should look if the bolt was locked while closing + UpdateBoltLightStatus(uid, component); + } + + public void SetBoltsWithAudio(EntityUid uid, DoorBoltComponent component, bool newBolts) + { + if (newBolts == component.BoltsDown) + return; + + component.BoltsDown = newBolts; + Audio.PlayPvs(newBolts ? component.BoltDownSound : component.BoltUpSound, uid); + UpdateBoltLightStatus(uid, component); + } + + public bool IsBolted(EntityUid uid, DoorBoltComponent? component = null) + { + if (!Resolve(uid, ref component)) + { + return false; + } + + return component.BoltsDown; + } +} + diff --git a/Content.Server/Doors/Systems/DoorSystem.cs b/Content.Server/Doors/Systems/DoorSystem.cs index c263f9c437..b4ecee928f 100644 --- a/Content.Server/Doors/Systems/DoorSystem.cs +++ b/Content.Server/Doors/Systems/DoorSystem.cs @@ -27,7 +27,7 @@ namespace Content.Server.Doors.Systems; public sealed class DoorSystem : SharedDoorSystem { - [Dependency] private readonly AirlockSystem _airlock = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly AirtightSystem _airtightSystem = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!; @@ -231,7 +231,7 @@ public sealed class DoorSystem : SharedDoorSystem { if(TryComp(uid, out var airlockComponent)) { - if (airlockComponent.BoltsDown || !this.IsPowered(uid, EntityManager)) + if (_bolts.IsBolted(uid) || !this.IsPowered(uid, EntityManager)) return; if (door.State == DoorState.Closed) @@ -255,8 +255,8 @@ public sealed class DoorSystem : SharedDoorSystem if (door.OpenSound != null) PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted); - if(lastState == DoorState.Emagging && TryComp(uid, out var airlockComponent)) - _airlock.SetBoltsWithAudio(uid, airlockComponent, !airlockComponent.BoltsDown); + if(lastState == DoorState.Emagging && TryComp(uid, out var doorBoltComponent)) + _bolts.SetBoltsWithAudio(uid, doorBoltComponent, !doorBoltComponent.BoltsDown); } protected override void CheckDoorBump(DoorComponent component, PhysicsComponent body) diff --git a/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs b/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs index 90ce33f440..7b81d952f4 100644 --- a/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs +++ b/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs @@ -6,31 +6,31 @@ using Content.Shared.Wires; namespace Content.Server.Doors; -public sealed class DoorBoltLightWireAction : ComponentWireAction +public sealed class DoorBoltLightWireAction : ComponentWireAction { public override Color Color { get; set; } = Color.Lime; public override string Name { get; set; } = "wire-name-bolt-light"; - public override StatusLightState? GetLightState(Wire wire, AirlockComponent comp) + public override StatusLightState? GetLightState(Wire wire, DoorBoltComponent comp) => comp.BoltLightsEnabled ? StatusLightState.On : StatusLightState.Off; public override object StatusKey { get; } = AirlockWireStatus.BoltLightIndicator; - public override bool Cut(EntityUid user, Wire wire, AirlockComponent door) + public override bool Cut(EntityUid user, Wire wire, DoorBoltComponent door) { - EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, false); + EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, false); return true; } - public override bool Mend(EntityUid user, Wire wire, AirlockComponent door) + public override bool Mend(EntityUid user, Wire wire, DoorBoltComponent door) { - EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, true); + EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, true); return true; } - public override void Pulse(EntityUid user, Wire wire, AirlockComponent door) + public override void Pulse(EntityUid user, Wire wire, DoorBoltComponent door) { - EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, !door.BoltLightsEnabled); + EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, !door.BoltLightsEnabled); } } diff --git a/Content.Server/Doors/WireActions/DoorBoltWireAction.cs b/Content.Server/Doors/WireActions/DoorBoltWireAction.cs index ca311b296c..b80611e64e 100644 --- a/Content.Server/Doors/WireActions/DoorBoltWireAction.cs +++ b/Content.Server/Doors/WireActions/DoorBoltWireAction.cs @@ -7,36 +7,36 @@ using Content.Shared.Wires; namespace Content.Server.Doors; -public sealed class DoorBoltWireAction : ComponentWireAction +public sealed class DoorBoltWireAction : ComponentWireAction { public override Color Color { get; set; } = Color.Red; public override string Name { get; set; } = "wire-name-door-bolt"; - - public override StatusLightState? GetLightState(Wire wire, AirlockComponent comp) + + public override StatusLightState? GetLightState(Wire wire, DoorBoltComponent comp) => comp.BoltsDown ? StatusLightState.On : StatusLightState.Off; public override object StatusKey { get; } = AirlockWireStatus.BoltIndicator; - public override bool Cut(EntityUid user, Wire wire, AirlockComponent airlock) + public override bool Cut(EntityUid user, Wire wire, DoorBoltComponent airlock) { - EntityManager.System().SetBoltWireCut(airlock, true); + EntityManager.System().SetBoltWireCut(airlock, true); if (!airlock.BoltsDown && IsPowered(wire.Owner)) - EntityManager.System().SetBoltsWithAudio(wire.Owner, airlock, true); + EntityManager.System().SetBoltsWithAudio(wire.Owner, airlock, true); return true; } - public override bool Mend(EntityUid user, Wire wire, AirlockComponent door) + public override bool Mend(EntityUid user, Wire wire, DoorBoltComponent door) { - EntityManager.System().SetBoltWireCut(door, true); + EntityManager.System().SetBoltWireCut(door, true); return true; } - public override void Pulse(EntityUid user, Wire wire, AirlockComponent door) + public override void Pulse(EntityUid user, Wire wire, DoorBoltComponent door) { if (IsPowered(wire.Owner)) - EntityManager.System().SetBoltsWithAudio(wire.Owner, door, !door.BoltsDown); + EntityManager.System().SetBoltsWithAudio(wire.Owner, door, !door.BoltsDown); else if (!door.BoltsDown) - EntityManager.System().SetBoltsWithAudio(wire.Owner, door, true); + EntityManager.System().SetBoltsWithAudio(wire.Owner, door, true); } } diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index eff1d71f63..cd2d356ef2 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -39,7 +39,7 @@ public sealed class MagicSystem : EntitySystem [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly AirlockSystem _airlock = default!; + [Dependency] private readonly DoorBoltSystem _boltsSystem = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedDoorSystem _doorSystem = default!; @@ -303,8 +303,8 @@ public sealed class MagicSystem : EntitySystem //Look for doors and don't open them if they're already open. foreach (var entity in _lookup.GetEntitiesInRange(coords, args.Range)) { - if (TryComp(entity, out var airlock)) - _airlock.SetBoltsDown(entity, airlock, false); + if (TryComp(entity, out var bolts)) + _boltsSystem.SetBoltsDown(entity, bolts, false); if (TryComp(entity, out var doorComp) && doorComp.State is not DoorState.Open) _doorSystem.StartOpening(doorComp.Owner); diff --git a/Content.Server/Remotes/DoorRemoteSystem.cs b/Content.Server/Remotes/DoorRemoteSystem.cs index 8bb88abef8..ad6b1b12ae 100644 --- a/Content.Server/Remotes/DoorRemoteSystem.cs +++ b/Content.Server/Remotes/DoorRemoteSystem.cs @@ -17,6 +17,7 @@ namespace Content.Server.Remotes public sealed class DoorRemoteSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly AirlockSystem _airlock = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; @@ -88,10 +89,13 @@ namespace Content.Server.Remotes _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)}: {doorComp.State}"); break; case OperatingMode.ToggleBolts: - if (!airlockComp.BoltWireCut) + if (TryComp(args.Target, out var boltsComp)) { - _airlock.SetBoltsWithAudio(args.Target.Value, airlockComp, !airlockComp.BoltsDown); - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to {(airlockComp.BoltsDown ? "" : "un")}bolt it"); + if (!boltsComp.BoltWireCut) + { + _bolts.SetBoltsWithAudio(args.Target.Value, boltsComp, !boltsComp.BoltsDown); + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to {(boltsComp.BoltsDown ? "" : "un")}bolt it"); + } } break; case OperatingMode.ToggleEmergencyAccess: diff --git a/Content.Server/Shuttles/Systems/DockingSystem.cs b/Content.Server/Shuttles/Systems/DockingSystem.cs index 26dfd68b60..cc61491be3 100644 --- a/Content.Server/Shuttles/Systems/DockingSystem.cs +++ b/Content.Server/Shuttles/Systems/DockingSystem.cs @@ -18,7 +18,7 @@ namespace Content.Server.Shuttles.Systems public sealed partial class DockingSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly AirlockSystem _airlocks = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; [Dependency] private readonly PathfindingSystem _pathfinding = default!; @@ -355,9 +355,9 @@ namespace Content.Server.Shuttles.Systems if (_doorSystem.TryOpen(dockAUid, doorA)) { doorA.ChangeAirtight = false; - if (TryComp(dockAUid, out var airlockA)) + if (TryComp(dockAUid, out var airlockA)) { - _airlocks.SetBoltsWithAudio(dockAUid, airlockA, true); + _bolts.SetBoltsWithAudio(dockAUid, airlockA, true); } } } @@ -367,9 +367,9 @@ namespace Content.Server.Shuttles.Systems if (_doorSystem.TryOpen(dockBUid, doorB)) { doorB.ChangeAirtight = false; - if (TryComp(dockBUid, out var airlockB)) + if (TryComp(dockBUid, out var airlockB)) { - _airlocks.SetBoltsWithAudio(dockBUid, airlockB, true); + _bolts.SetBoltsWithAudio(dockBUid, airlockB, true); } } } @@ -453,14 +453,14 @@ namespace Content.Server.Shuttles.Systems if (dock.DockedWith == null) return; - if (TryComp(dockUid, out var airlockA)) + if (TryComp(dockUid, out var airlockA)) { - _airlocks.SetBoltsWithAudio(dockUid, airlockA, false); + _bolts.SetBoltsWithAudio(dockUid, airlockA, false); } - if (TryComp(dock.DockedWith, out var airlockB)) + if (TryComp(dock.DockedWith, out var airlockB)) { - _airlocks.SetBoltsWithAudio(dock.DockedWith.Value, airlockB, false); + _bolts.SetBoltsWithAudio(dock.DockedWith.Value, airlockB, false); } if (TryComp(dockUid, out DoorComponent? doorA)) diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index fb3b7b7979..18a5000bcf 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -393,7 +393,7 @@ public sealed partial class ShuttleSystem private void SetDockBolts(EntityUid uid, bool enabled) { - var query = AllEntityQuery(); + var query = AllEntityQuery(); while (query.MoveNext(out var doorUid, out _, out var door, out var xform)) { @@ -401,7 +401,7 @@ public sealed partial class ShuttleSystem continue; _doors.TryClose(doorUid); - _airlock.SetBoltsWithAudio(doorUid, door, enabled); + _bolts.SetBoltsWithAudio(doorUid, door, enabled); } } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 2ca053f8cd..2914cb0f1f 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -23,10 +23,10 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem { [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly AirlockSystem _airlock = default!; [Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly DockingSystem _dockSystem = default!; [Dependency] private readonly DoorSystem _doors = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; diff --git a/Content.Shared/Doors/Components/AirlockComponent.cs b/Content.Shared/Doors/Components/AirlockComponent.cs index 2d343da615..2578dc7301 100644 --- a/Content.Shared/Doors/Components/AirlockComponent.cs +++ b/Content.Shared/Doors/Components/AirlockComponent.cs @@ -22,18 +22,6 @@ public sealed class AirlockComponent : Component [DataField("emergencyAccess")] public bool EmergencyAccess = false; - /// - /// 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"); - /// /// Pry modifier for a powered airlock. /// Most anything that can pry powered has a pry speed bonus, @@ -55,24 +43,6 @@ public sealed class AirlockComponent : Component [DataField("keepOpenIfClicked")] public bool KeepOpenIfClicked = false; - /// - /// Whether the door bolts are currently deployed. - /// - [ViewVariables] - public bool BoltsDown; - - /// - /// Whether the bolt lights are currently enabled. - /// - [ViewVariables] - public bool BoltLightsEnabled = true; - - /// - /// True if the bolt wire is cut, which will force the airlock to always be bolted as long as it has power. - /// - [ViewVariables] - public bool BoltWireCut; - /// /// Whether the airlock should auto close. This value is reset every time the airlock closes. /// diff --git a/Content.Shared/Doors/Components/DoorBoltComponent.cs b/Content.Shared/Doors/Components/DoorBoltComponent.cs new file mode 100644 index 0000000000..13d2be47ff --- /dev/null +++ b/Content.Shared/Doors/Components/DoorBoltComponent.cs @@ -0,0 +1,46 @@ +using Content.Shared.Doors.Systems; +using Content.Shared.MachineLinking; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Doors.Components; + +/// +/// Companion component to DoorComponent that handles bolt-specific behavior. +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedDoorBoltSystem))] +public sealed class DoorBoltComponent : Component +{ + /// + /// Sound to play when the bolts on the airlock go up. + /// + [DataField("boltUpSound"), ViewVariables(VVAccess.ReadWrite)] + public SoundSpecifier BoltUpSound = new SoundPathSpecifier("/Audio/Machines/boltsup.ogg"); + + /// + /// Sound to play when the bolts on the airlock go down. + /// + [DataField("boltDownSound"), ViewVariables(VVAccess.ReadWrite)] + public SoundSpecifier BoltDownSound = new SoundPathSpecifier("/Audio/Machines/boltsdown.ogg"); + + /// + /// Whether the door bolts are currently deployed. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool BoltsDown; + + /// + /// Whether the bolt lights are currently enabled. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool BoltLightsEnabled = true; + + /// + /// True if the bolt wire is cut, which will force the airlock to always be bolted as long as it has power. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool BoltWireCut; +} diff --git a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs index d3fa217bda..1274e33985 100644 --- a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs +++ b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs @@ -7,7 +7,6 @@ namespace Content.Shared.Doors.Systems; public abstract class SharedAirlockSystem : EntitySystem { [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; - [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly SharedDoorSystem DoorSystem = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; @@ -64,9 +63,4 @@ public abstract class SharedAirlockSystem : EntitySystem { component.Safety = value; } - - public void SetBoltWireCut(AirlockComponent component, bool value) - { - component.BoltWireCut = value; - } } diff --git a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs new file mode 100644 index 0000000000..ed1e9d4351 --- /dev/null +++ b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared.Doors.Components; +using Content.Shared.Popups; + +namespace Content.Shared.Doors.Systems; + +public abstract class SharedDoorBoltSystem : EntitySystem +{ + + [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; + [Dependency] protected readonly SharedAudioSystem Audio = default!; + [Dependency] private readonly SharedPopupSystem Popup = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnBeforeDoorOpened); + SubscribeLocalEvent(OnBeforeDoorClosed); + SubscribeLocalEvent(OnBeforeDoorDenied); + SubscribeLocalEvent(OnDoorPry); + + } + + private void OnDoorPry(EntityUid uid, DoorBoltComponent component, BeforeDoorPryEvent args) + { + if (component.BoltsDown) + { + Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User); + args.Cancel(); + } + } + + private void OnBeforeDoorOpened(EntityUid uid, DoorBoltComponent component, BeforeDoorOpenedEvent args) + { + if (component.BoltsDown) + args.Cancel(); + } + + private void OnBeforeDoorClosed(EntityUid uid, DoorBoltComponent component, BeforeDoorClosedEvent args) + { + if (component.BoltsDown) + args.Cancel(); + } + + private void OnBeforeDoorDenied(EntityUid uid, DoorBoltComponent component, BeforeDoorDeniedEvent args) + { + if (component.BoltsDown) + args.Cancel(); + } + + public void SetBoltWireCut(DoorBoltComponent component, bool value) + { + component.BoltWireCut = value; + } +} diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index b314022a98..304aea8992 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -66,6 +66,7 @@ fuel: 3 time: 3 - type: Airlock + - type: DoorBolt - type: Appearance - type: WiresVisuals - type: ApcPowerReceiver diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml index cf25be34c6..cb69d8e8df 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml @@ -59,6 +59,7 @@ fuel: 10 time: 10 - type: Airlock + - type: DoorBolt - type: Appearance - type: WiresVisuals - type: ApcPowerReceiver diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml index 2f8353badd..d975769416 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml @@ -112,6 +112,7 @@ openUnlitVisible: true # needed so that windoors will close regardless of whether there are people in it; it doesn't crush after all safety: false + - type: DoorBolt - type: Electrified enabled: false usesApcPower: true diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml index 853c86f48e..6911d3132f 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml @@ -85,7 +85,7 @@ conditions: - !type:EntityAnchored {} - !type:DoorWelded {} - - !type:AirlockBolted + - !type:DoorBolted value: false - !type:WirePanel {} - !type:AllWiresCut @@ -123,7 +123,7 @@ conditions: - !type:EntityAnchored {} - !type:DoorWelded {} - - !type:AirlockBolted + - !type:DoorBolted value: false - !type:WirePanel {} - !type:AllWiresCut diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/shuttle.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/shuttle.yml index 2af75f6afc..dc05edd8fb 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/shuttle.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/shuttle.yml @@ -153,7 +153,7 @@ conditions: - !type:EntityAnchored {} - !type:DoorWelded {} - - !type:AirlockBolted + - !type:DoorBolted value: false - !type:WirePanel {} steps: @@ -185,7 +185,7 @@ conditions: - !type:EntityAnchored {} - !type:DoorWelded {} - - !type:AirlockBolted + - !type:DoorBolted value: false - !type:WirePanel {} steps: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/windoor.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/windoor.yml index 53caf00ba8..a991884acb 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/windoor.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/windoor.yml @@ -108,7 +108,7 @@ - to: wired conditions: - !type:EntityAnchored {} - - !type:AirlockBolted + - !type:DoorBolted value: false - !type:WirePanel {} - !type:AllWiresCut @@ -206,7 +206,7 @@ - to: wired conditions: - !type:EntityAnchored {} - - !type:AirlockBolted + - !type:DoorBolted value: false - !type:WirePanel {} - !type:ContainerNotEmpty # TODO ShadowCommander: Remove when map gets updated