Split Door Bolt functionality out of AirlockDoor (#16354)

This commit is contained in:
Tom Leys
2023-06-01 02:23:35 +12:00
committed by GitHub
parent f419c20c49
commit a196756124
26 changed files with 283 additions and 161 deletions

View File

@@ -86,7 +86,8 @@ public sealed class AirlockSystem : SharedAirlockSystem
if (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.Powered, out var powered, args.Component) && powered) if (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.Powered, out var powered, args.Component) && powered)
{ {
boltedVisible = _appearanceSystem.TryGetData<bool>(uid, DoorVisuals.BoltLights, out var lights, args.Component) && lights; boltedVisible = _appearanceSystem.TryGetData<bool>(uid, DoorVisuals.BoltLights, out var lights, args.Component)
&& lights && state == DoorState.Closed;
emergencyLightsVisible = _appearanceSystem.TryGetData<bool>(uid, DoorVisuals.EmergencyLights, out var eaLights, args.Component) && eaLights; emergencyLightsVisible = _appearanceSystem.TryGetData<bool>(uid, DoorVisuals.EmergencyLights, out var eaLights, args.Component) && eaLights;
unlitVisible = unlitVisible =
state == DoorState.Closing state == DoorState.Closing

View File

@@ -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.
}

View File

@@ -38,6 +38,7 @@ namespace Content.IntegrationTests.Tests.Doors
components: components:
- type: Door - type: Door
- type: Airlock - type: Airlock
- type: DoorBolt
- type: ApcPowerReceiver - type: ApcPowerReceiver
needsPower: false needsPower: false
- type: Physics - type: Physics

View File

@@ -39,6 +39,7 @@ namespace Content.Server.Administration.Systems;
public sealed partial class AdminVerbSystem public sealed partial class AdminVerbSystem
{ {
[Dependency] private readonly DoorBoltSystem _boltsSystem = default!;
[Dependency] private readonly AirlockSystem _airlockSystem = default!; [Dependency] private readonly AirlockSystem _airlockSystem = default!;
[Dependency] private readonly StackSystem _stackSystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!;
[Dependency] private readonly SharedAccessSystem _accessSystem = default!; [Dependency] private readonly SharedAccessSystem _accessSystem = default!;
@@ -60,28 +61,31 @@ public sealed partial class AdminVerbSystem
if (_adminManager.HasAdminFlag(player, AdminFlags.Admin)) if (_adminManager.HasAdminFlag(player, AdminFlags.Admin))
{ {
if (TryComp<AirlockComponent>(args.Target, out var airlock)) if (TryComp<DoorBoltComponent>(args.Target, out var bolts))
{ {
Verb bolt = new() Verb bolt = new()
{ {
Text = airlock.BoltsDown ? "Unbolt" : "Bolt", Text = bolts.BoltsDown ? "Unbolt" : "Bolt",
Category = VerbCategory.Tricks, Category = VerbCategory.Tricks,
Icon = airlock.BoltsDown Icon = bolts.BoltsDown
? new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/unbolt.png")) ? new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/unbolt.png"))
: new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bolt.png")), : new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bolt.png")),
Act = () => Act = () =>
{ {
_airlockSystem.SetBoltsWithAudio(args.Target, airlock, !airlock.BoltsDown); _boltsSystem.SetBoltsWithAudio(args.Target, bolts, !bolts.BoltsDown);
}, },
Impact = LogImpact.Medium, Impact = LogImpact.Medium,
Message = Loc.GetString(airlock.BoltsDown Message = Loc.GetString(bolts.BoltsDown
? "admin-trick-unbolt-description" ? "admin-trick-unbolt-description"
: "admin-trick-bolt-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); args.Verbs.Add(bolt);
}
if (TryComp<AirlockComponent>(args.Target, out var airlock))
{
Verb emergencyAccess = new() Verb emergencyAccess = new()
{ {
Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On", Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",

View File

@@ -7,14 +7,14 @@ namespace Content.Server.Construction.Conditions
{ {
[UsedImplicitly] [UsedImplicitly]
[DataDefinition] [DataDefinition]
public sealed class AirlockBolted : IGraphCondition public sealed class DoorBolted : IGraphCondition
{ {
[DataField("value")] [DataField("value")]
public bool Value { get; private set; } = true; public bool Value { get; private set; } = true;
public bool Condition(EntityUid uid, IEntityManager entityManager) public bool Condition(EntityUid uid, IEntityManager entityManager)
{ {
if (!entityManager.TryGetComponent(uid, out AirlockComponent? airlock)) if (!entityManager.TryGetComponent(uid, out DoorBoltComponent? airlock))
return true; return true;
return airlock.BoltsDown == Value; return airlock.BoltsDown == Value;
@@ -26,7 +26,7 @@ namespace Content.Server.Construction.Conditions
var entMan = IoCManager.Resolve<IEntityManager>(); var entMan = IoCManager.Resolve<IEntityManager>();
if (!entMan.TryGetComponent(entity, out AirlockComponent? airlock)) return false; if (!entMan.TryGetComponent(entity, out DoorBoltComponent? airlock)) return false;
if (airlock.BoltsDown != Value) if (airlock.BoltsDown != Value)
{ {

View File

@@ -11,7 +11,7 @@ namespace Content.Server.DeviceLinking.Systems
[UsedImplicitly] [UsedImplicitly]
public sealed class DoorSignalControlSystem : EntitySystem 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 DoorSystem _doorSystem = default!;
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!; [Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
@@ -67,18 +67,18 @@ namespace Content.Server.DeviceLinking.Systems
{ {
if (state == SignalState.High) if (state == SignalState.High)
{ {
if(TryComp<AirlockComponent>(uid, out var airlockComponent)) if(TryComp<DoorBoltComponent>(uid, out var bolts))
_airlockSystem.SetBoltsWithAudio(uid, airlockComponent, true); _bolts.SetBoltsWithAudio(uid, bolts, true);
} }
else if (state == SignalState.Momentary) else if (state == SignalState.Momentary)
{ {
if (TryComp<AirlockComponent>(uid, out var airlockComponent)) if (TryComp<DoorBoltComponent>(uid, out var bolts))
_airlockSystem.SetBoltsWithAudio(uid, airlockComponent, newBolts: !airlockComponent.BoltsDown); _bolts.SetBoltsWithAudio(uid, bolts, newBolts: !bolts.BoltsDown);
} }
else else
{ {
if(TryComp<AirlockComponent>(uid, out var airlockComponent)) if(TryComp<DoorBoltComponent>(uid, out var bolts))
_airlockSystem.SetBoltsWithAudio(uid, airlockComponent, false); _bolts.SetBoltsWithAudio(uid, bolts, false);
} }
} }
} }

View File

@@ -18,6 +18,7 @@ namespace Content.Server.Doors.Systems
[Dependency] private readonly WiresSystem _wiresSystem = default!; [Dependency] private readonly WiresSystem _wiresSystem = default!;
[Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly PowerReceiverSystem _power = default!;
[Dependency] private readonly SignalLinkerSystem _signalSystem = default!; [Dependency] private readonly SignalLinkerSystem _signalSystem = default!;
[Dependency] private readonly DoorBoltSystem _bolts = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -70,14 +71,8 @@ namespace Content.Server.Doors.Systems
} }
else else
{ {
if (component.BoltWireCut)
SetBoltsWithAudio(uid, component, true);
UpdateAutoClose(uid, door: door); UpdateAutoClose(uid, door: door);
} }
// BoltLights also got out
UpdateBoltLightStatus(uid, component);
} }
private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) 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); _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 // If the door is closed, we should look if the bolt was locked while closing
UpdateBoltLightStatus(uid, component);
UpdateAutoClose(uid, component); UpdateAutoClose(uid, component);
// Make sure the airlock auto closes again next time it is opened // 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) 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 (this.IsPowered(uid, EntityManager))
{ {
if (HasComp<ToolForcePoweredComponent>(args.Tool)) if (HasComp<ToolForcePoweredComponent>(args.Tool))
@@ -197,52 +185,7 @@ namespace Content.Server.Doors.Systems
public bool CanChangeState(EntityUid uid, AirlockComponent component) public bool CanChangeState(EntityUid uid, AirlockComponent component)
{ {
return this.IsPowered(uid, EntityManager) && !component.BoltsDown; return this.IsPowered(uid, EntityManager) && !_bolts.IsBolted(uid);
}
public void UpdateBoltLightStatus(EntityUid uid, AirlockComponent component)
{
if (!TryComp<AppearanceComponent>(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<DoorComponent>(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);
} }
} }
} }

View File

@@ -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<DoorBoltComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<DoorBoltComponent, DoorStateChangedEvent>(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<AppearanceComponent>(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;
}
}

View File

@@ -27,7 +27,7 @@ namespace Content.Server.Doors.Systems;
public sealed class DoorSystem : SharedDoorSystem 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 AirtightSystem _airtightSystem = default!;
[Dependency] private readonly SharedToolSystem _toolSystem = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!;
@@ -231,7 +231,7 @@ public sealed class DoorSystem : SharedDoorSystem
{ {
if(TryComp<AirlockComponent>(uid, out var airlockComponent)) if(TryComp<AirlockComponent>(uid, out var airlockComponent))
{ {
if (airlockComponent.BoltsDown || !this.IsPowered(uid, EntityManager)) if (_bolts.IsBolted(uid) || !this.IsPowered(uid, EntityManager))
return; return;
if (door.State == DoorState.Closed) if (door.State == DoorState.Closed)
@@ -255,8 +255,8 @@ public sealed class DoorSystem : SharedDoorSystem
if (door.OpenSound != null) if (door.OpenSound != null)
PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted); PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted);
if(lastState == DoorState.Emagging && TryComp<AirlockComponent>(uid, out var airlockComponent)) if(lastState == DoorState.Emagging && TryComp<DoorBoltComponent>(uid, out var doorBoltComponent))
_airlock.SetBoltsWithAudio(uid, airlockComponent, !airlockComponent.BoltsDown); _bolts.SetBoltsWithAudio(uid, doorBoltComponent, !doorBoltComponent.BoltsDown);
} }
protected override void CheckDoorBump(DoorComponent component, PhysicsComponent body) protected override void CheckDoorBump(DoorComponent component, PhysicsComponent body)

View File

@@ -6,31 +6,31 @@ using Content.Shared.Wires;
namespace Content.Server.Doors; namespace Content.Server.Doors;
public sealed class DoorBoltLightWireAction : ComponentWireAction<AirlockComponent> public sealed class DoorBoltLightWireAction : ComponentWireAction<DoorBoltComponent>
{ {
public override Color Color { get; set; } = Color.Lime; public override Color Color { get; set; } = Color.Lime;
public override string Name { get; set; } = "wire-name-bolt-light"; 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; => comp.BoltLightsEnabled ? StatusLightState.On : StatusLightState.Off;
public override object StatusKey { get; } = AirlockWireStatus.BoltLightIndicator; 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<AirlockSystem>().SetBoltLightsEnabled(wire.Owner, door, false); EntityManager.System<DoorBoltSystem>().SetBoltLightsEnabled(wire.Owner, door, false);
return 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<AirlockSystem>().SetBoltLightsEnabled(wire.Owner, door, true); EntityManager.System<DoorBoltSystem>().SetBoltLightsEnabled(wire.Owner, door, true);
return 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<AirlockSystem>().SetBoltLightsEnabled(wire.Owner, door, !door.BoltLightsEnabled); EntityManager.System<DoorBoltSystem>().SetBoltLightsEnabled(wire.Owner, door, !door.BoltLightsEnabled);
} }
} }

View File

@@ -7,36 +7,36 @@ using Content.Shared.Wires;
namespace Content.Server.Doors; namespace Content.Server.Doors;
public sealed class DoorBoltWireAction : ComponentWireAction<AirlockComponent> public sealed class DoorBoltWireAction : ComponentWireAction<DoorBoltComponent>
{ {
public override Color Color { get; set; } = Color.Red; public override Color Color { get; set; } = Color.Red;
public override string Name { get; set; } = "wire-name-door-bolt"; 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; => comp.BoltsDown ? StatusLightState.On : StatusLightState.Off;
public override object StatusKey { get; } = AirlockWireStatus.BoltIndicator; 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<SharedAirlockSystem>().SetBoltWireCut(airlock, true); EntityManager.System<DoorBoltSystem>().SetBoltWireCut(airlock, true);
if (!airlock.BoltsDown && IsPowered(wire.Owner)) if (!airlock.BoltsDown && IsPowered(wire.Owner))
EntityManager.System<AirlockSystem>().SetBoltsWithAudio(wire.Owner, airlock, true); EntityManager.System<DoorBoltSystem>().SetBoltsWithAudio(wire.Owner, airlock, true);
return 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<SharedAirlockSystem>().SetBoltWireCut(door, true); EntityManager.System<DoorBoltSystem>().SetBoltWireCut(door, true);
return 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)) if (IsPowered(wire.Owner))
EntityManager.System<AirlockSystem>().SetBoltsWithAudio(wire.Owner, door, !door.BoltsDown); EntityManager.System<DoorBoltSystem>().SetBoltsWithAudio(wire.Owner, door, !door.BoltsDown);
else if (!door.BoltsDown) else if (!door.BoltsDown)
EntityManager.System<AirlockSystem>().SetBoltsWithAudio(wire.Owner, door, true); EntityManager.System<DoorBoltSystem>().SetBoltsWithAudio(wire.Owner, door, true);
} }
} }

View File

@@ -39,7 +39,7 @@ public sealed class MagicSystem : EntitySystem
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = 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 BodySystem _bodySystem = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedDoorSystem _doorSystem = 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. //Look for doors and don't open them if they're already open.
foreach (var entity in _lookup.GetEntitiesInRange(coords, args.Range)) foreach (var entity in _lookup.GetEntitiesInRange(coords, args.Range))
{ {
if (TryComp<AirlockComponent>(entity, out var airlock)) if (TryComp<DoorBoltComponent>(entity, out var bolts))
_airlock.SetBoltsDown(entity, airlock, false); _boltsSystem.SetBoltsDown(entity, bolts, false);
if (TryComp<DoorComponent>(entity, out var doorComp) && doorComp.State is not DoorState.Open) if (TryComp<DoorComponent>(entity, out var doorComp) && doorComp.State is not DoorState.Open)
_doorSystem.StartOpening(doorComp.Owner); _doorSystem.StartOpening(doorComp.Owner);

View File

@@ -17,6 +17,7 @@ namespace Content.Server.Remotes
public sealed class DoorRemoteSystem : EntitySystem public sealed class DoorRemoteSystem : EntitySystem
{ {
[Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly DoorBoltSystem _bolts = default!;
[Dependency] private readonly AirlockSystem _airlock = default!; [Dependency] private readonly AirlockSystem _airlock = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly DoorSystem _doorSystem = 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}"); _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)}: {doorComp.State}");
break; break;
case OperatingMode.ToggleBolts: case OperatingMode.ToggleBolts:
if (!airlockComp.BoltWireCut) if (TryComp<DoorBoltComponent>(args.Target, out var boltsComp))
{ {
_airlock.SetBoltsWithAudio(args.Target.Value, airlockComp, !airlockComp.BoltsDown); if (!boltsComp.BoltWireCut)
_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"); {
_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; break;
case OperatingMode.ToggleEmergencyAccess: case OperatingMode.ToggleEmergencyAccess:

View File

@@ -18,7 +18,7 @@ namespace Content.Server.Shuttles.Systems
public sealed partial class DockingSystem : EntitySystem public sealed partial class DockingSystem : EntitySystem
{ {
[Dependency] private readonly IMapManager _mapManager = default!; [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 DoorSystem _doorSystem = default!;
[Dependency] private readonly FixtureSystem _fixtureSystem = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!;
[Dependency] private readonly PathfindingSystem _pathfinding = default!; [Dependency] private readonly PathfindingSystem _pathfinding = default!;
@@ -355,9 +355,9 @@ namespace Content.Server.Shuttles.Systems
if (_doorSystem.TryOpen(dockAUid, doorA)) if (_doorSystem.TryOpen(dockAUid, doorA))
{ {
doorA.ChangeAirtight = false; doorA.ChangeAirtight = false;
if (TryComp<AirlockComponent>(dockAUid, out var airlockA)) if (TryComp<DoorBoltComponent>(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)) if (_doorSystem.TryOpen(dockBUid, doorB))
{ {
doorB.ChangeAirtight = false; doorB.ChangeAirtight = false;
if (TryComp<AirlockComponent>(dockBUid, out var airlockB)) if (TryComp<DoorBoltComponent>(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) if (dock.DockedWith == null)
return; return;
if (TryComp<AirlockComponent>(dockUid, out var airlockA)) if (TryComp<DoorBoltComponent>(dockUid, out var airlockA))
{ {
_airlocks.SetBoltsWithAudio(dockUid, airlockA, false); _bolts.SetBoltsWithAudio(dockUid, airlockA, false);
} }
if (TryComp<AirlockComponent>(dock.DockedWith, out var airlockB)) if (TryComp<DoorBoltComponent>(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)) if (TryComp(dockUid, out DoorComponent? doorA))

View File

@@ -393,7 +393,7 @@ public sealed partial class ShuttleSystem
private void SetDockBolts(EntityUid uid, bool enabled) private void SetDockBolts(EntityUid uid, bool enabled)
{ {
var query = AllEntityQuery<DockingComponent, AirlockComponent, TransformComponent>(); var query = AllEntityQuery<DockingComponent, DoorBoltComponent, TransformComponent>();
while (query.MoveNext(out var doorUid, out _, out var door, out var xform)) while (query.MoveNext(out var doorUid, out _, out var door, out var xform))
{ {
@@ -401,7 +401,7 @@ public sealed partial class ShuttleSystem
continue; continue;
_doors.TryClose(doorUid); _doors.TryClose(doorUid);
_airlock.SetBoltsWithAudio(doorUid, door, enabled); _bolts.SetBoltsWithAudio(doorUid, door, enabled);
} }
} }

View File

@@ -23,10 +23,10 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
{ {
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly AirlockSystem _airlock = default!;
[Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly BodySystem _bobby = default!;
[Dependency] private readonly DockingSystem _dockSystem = default!; [Dependency] private readonly DockingSystem _dockSystem = default!;
[Dependency] private readonly DoorSystem _doors = default!; [Dependency] private readonly DoorSystem _doors = default!;
[Dependency] private readonly DoorBoltSystem _bolts = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly FixtureSystem _fixtures = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly MapLoaderSystem _loader = default!;

View File

@@ -22,18 +22,6 @@ public sealed class AirlockComponent : Component
[DataField("emergencyAccess")] [DataField("emergencyAccess")]
public bool EmergencyAccess = false; public bool EmergencyAccess = false;
/// <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>
/// Pry modifier for a powered airlock. /// Pry modifier for a powered airlock.
/// Most anything that can pry powered has a pry speed bonus, /// Most anything that can pry powered has a pry speed bonus,
@@ -55,24 +43,6 @@ public sealed class AirlockComponent : Component
[DataField("keepOpenIfClicked")] [DataField("keepOpenIfClicked")]
public bool KeepOpenIfClicked = false; public bool KeepOpenIfClicked = false;
/// <summary>
/// Whether the door bolts are currently deployed.
/// </summary>
[ViewVariables]
public bool BoltsDown;
/// <summary>
/// Whether the bolt lights are currently enabled.
/// </summary>
[ViewVariables]
public bool BoltLightsEnabled = true;
/// <summary>
/// True if the bolt wire is cut, which will force the airlock to always be bolted as long as it has power.
/// </summary>
[ViewVariables]
public bool BoltWireCut;
/// <summary> /// <summary>
/// Whether the airlock should auto close. This value is reset every time the airlock closes. /// Whether the airlock should auto close. This value is reset every time the airlock closes.
/// </summary> /// </summary>

View File

@@ -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;
/// <summary>
/// Companion component to DoorComponent that handles bolt-specific behavior.
/// </summary>
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedDoorBoltSystem))]
public sealed class DoorBoltComponent : Component
{
/// <summary>
/// Sound to play when the bolts on the airlock go up.
/// </summary>
[DataField("boltUpSound"), ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier BoltUpSound = new SoundPathSpecifier("/Audio/Machines/boltsup.ogg");
/// <summary>
/// Sound to play when the bolts on the airlock go down.
/// </summary>
[DataField("boltDownSound"), ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier BoltDownSound = new SoundPathSpecifier("/Audio/Machines/boltsdown.ogg");
/// <summary>
/// Whether the door bolts are currently deployed.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool BoltsDown;
/// <summary>
/// Whether the bolt lights are currently enabled.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool BoltLightsEnabled = true;
/// <summary>
/// True if the bolt wire is cut, which will force the airlock to always be bolted as long as it has power.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool BoltWireCut;
}

View File

@@ -7,7 +7,6 @@ namespace Content.Shared.Doors.Systems;
public abstract class SharedAirlockSystem : EntitySystem public abstract class SharedAirlockSystem : EntitySystem
{ {
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
[Dependency] protected readonly SharedAudioSystem Audio = default!;
[Dependency] protected readonly SharedDoorSystem DoorSystem = default!; [Dependency] protected readonly SharedDoorSystem DoorSystem = default!;
[Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!;
@@ -64,9 +63,4 @@ public abstract class SharedAirlockSystem : EntitySystem
{ {
component.Safety = value; component.Safety = value;
} }
public void SetBoltWireCut(AirlockComponent component, bool value)
{
component.BoltWireCut = value;
}
} }

View File

@@ -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<DoorBoltComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorClosedEvent>(OnBeforeDoorClosed);
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorPryEvent>(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;
}
}

View File

@@ -66,6 +66,7 @@
fuel: 3 fuel: 3
time: 3 time: 3
- type: Airlock - type: Airlock
- type: DoorBolt
- type: Appearance - type: Appearance
- type: WiresVisuals - type: WiresVisuals
- type: ApcPowerReceiver - type: ApcPowerReceiver

View File

@@ -59,6 +59,7 @@
fuel: 10 fuel: 10
time: 10 time: 10
- type: Airlock - type: Airlock
- type: DoorBolt
- type: Appearance - type: Appearance
- type: WiresVisuals - type: WiresVisuals
- type: ApcPowerReceiver - type: ApcPowerReceiver

View File

@@ -112,6 +112,7 @@
openUnlitVisible: true openUnlitVisible: true
# needed so that windoors will close regardless of whether there are people in it; it doesn't crush after all # needed so that windoors will close regardless of whether there are people in it; it doesn't crush after all
safety: false safety: false
- type: DoorBolt
- type: Electrified - type: Electrified
enabled: false enabled: false
usesApcPower: true usesApcPower: true

View File

@@ -85,7 +85,7 @@
conditions: conditions:
- !type:EntityAnchored {} - !type:EntityAnchored {}
- !type:DoorWelded {} - !type:DoorWelded {}
- !type:AirlockBolted - !type:DoorBolted
value: false value: false
- !type:WirePanel {} - !type:WirePanel {}
- !type:AllWiresCut - !type:AllWiresCut
@@ -123,7 +123,7 @@
conditions: conditions:
- !type:EntityAnchored {} - !type:EntityAnchored {}
- !type:DoorWelded {} - !type:DoorWelded {}
- !type:AirlockBolted - !type:DoorBolted
value: false value: false
- !type:WirePanel {} - !type:WirePanel {}
- !type:AllWiresCut - !type:AllWiresCut

View File

@@ -153,7 +153,7 @@
conditions: conditions:
- !type:EntityAnchored {} - !type:EntityAnchored {}
- !type:DoorWelded {} - !type:DoorWelded {}
- !type:AirlockBolted - !type:DoorBolted
value: false value: false
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
@@ -185,7 +185,7 @@
conditions: conditions:
- !type:EntityAnchored {} - !type:EntityAnchored {}
- !type:DoorWelded {} - !type:DoorWelded {}
- !type:AirlockBolted - !type:DoorBolted
value: false value: false
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:

View File

@@ -108,7 +108,7 @@
- to: wired - to: wired
conditions: conditions:
- !type:EntityAnchored {} - !type:EntityAnchored {}
- !type:AirlockBolted - !type:DoorBolted
value: false value: false
- !type:WirePanel {} - !type:WirePanel {}
- !type:AllWiresCut - !type:AllWiresCut
@@ -206,7 +206,7 @@
- to: wired - to: wired
conditions: conditions:
- !type:EntityAnchored {} - !type:EntityAnchored {}
- !type:AirlockBolted - !type:DoorBolted
value: false value: false
- !type:WirePanel {} - !type:WirePanel {}
- !type:ContainerNotEmpty # TODO ShadowCommander: Remove when map gets updated - !type:ContainerNotEmpty # TODO ShadowCommander: Remove when map gets updated