Add Fire-fighting remote for Fire-doors (#16189)

This commit is contained in:
Tom Leys
2023-08-11 21:29:33 +12:00
committed by GitHub
parent 89250e375c
commit 4a55a000cb
10 changed files with 171 additions and 112 deletions

View File

@@ -5,7 +5,7 @@ namespace Content.Client.Doors;
public sealed class FirelockSystem : EntitySystem public sealed class FirelockSystem : EntitySystem
{ {
[Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!; [Dependency] protected readonly SharedAppearanceSystem _appearanceSystem = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -18,10 +18,23 @@ public sealed class FirelockSystem : EntitySystem
if (args.Sprite == null) if (args.Sprite == null)
return; return;
// Apply the closed lights bool to the sprite var boltedVisible = false;
bool unlitVisible = var unlitVisible = false;
(AppearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) &&
closedLights); if (!_appearanceSystem.TryGetData<DoorState>(uid, DoorVisuals.State, out var state, args.Component))
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible); state = DoorState.Closed;
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;
unlitVisible =
state == DoorState.Closing
|| state == DoorState.Opening
|| state == DoorState.Denying
|| (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) && closedLights);
}
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible && !boltedVisible);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseBolted, boltedVisible);
} }
} }

View File

@@ -4,7 +4,10 @@ using Content.Server.Atmos.Monitor.Systems;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Server.Remotes;
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor;
using Content.Shared.Doors; using Content.Shared.Doors;
@@ -25,6 +28,7 @@ namespace Content.Server.Doors.Systems
[Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!; [Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!; [Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
private static float _visualUpdateInterval = 0.5f; private static float _visualUpdateInterval = 0.5f;
private float _accumulatedFrameTime; private float _accumulatedFrameTime;
@@ -133,7 +137,10 @@ namespace Content.Server.Doors.Systems
private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, BeforeDoorOpenedEvent args) private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, BeforeDoorOpenedEvent args)
{ {
if (!this.IsPowered(uid, EntityManager) || IsHoldingPressureOrFire(uid, component)) // Give the Door remote the ability to force a firelock open even if it is holding back dangerous gas
var overrideAccess = (args.User != null) && _accessReaderSystem.IsAllowed(args.User.Value, uid);
if (!this.IsPowered(uid, EntityManager) || (!overrideAccess && IsHoldingPressureOrFire(uid, component)))
args.Cancel(); args.Cancel();
} }

View File

@@ -39,10 +39,14 @@ namespace Content.Server.Remotes
component.Mode = OperatingMode.ToggleBolts; component.Mode = OperatingMode.ToggleBolts;
switchMessageId = "door-remote-switch-state-toggle-bolts"; switchMessageId = "door-remote-switch-state-toggle-bolts";
break; break;
// Skip toggle bolts mode and move on from there (to emergency access)
case OperatingMode.ToggleBolts: case OperatingMode.ToggleBolts:
component.Mode = OperatingMode.ToggleEmergencyAccess; component.Mode = OperatingMode.ToggleEmergencyAccess;
switchMessageId = "door-remote-switch-state-toggle-emergency-access"; switchMessageId = "door-remote-switch-state-toggle-emergency-access";
break; break;
// Skip ToggleEmergencyAccess mode and move on from there (to door toggle)
case OperatingMode.ToggleEmergencyAccess: case OperatingMode.ToggleEmergencyAccess:
component.Mode = OperatingMode.OpenClose; component.Mode = OperatingMode.OpenClose;
switchMessageId = "door-remote-switch-state-open-close"; switchMessageId = "door-remote-switch-state-open-close";
@@ -56,15 +60,18 @@ namespace Content.Server.Remotes
private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, BeforeRangedInteractEvent args) private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, BeforeRangedInteractEvent args)
{ {
bool isAirlock = TryComp<AirlockComponent>(args.Target, out var airlockComp);
if (args.Handled if (args.Handled
|| args.Target == null || args.Target == null
|| !TryComp<DoorComponent>(args.Target, out var doorComp) // If it isn't a door we don't use it || !TryComp<DoorComponent>(args.Target, out var doorComp) // If it isn't a door we don't use it
|| !TryComp<AirlockComponent>(args.Target, out var airlockComp) // Remotes only work on airlocks
// The remote can be used anywhere the user can see the door. // The remote can be used anywhere the user can see the door.
// This doesn't work that well, but I don't know of an alternative // This doesn't work that well, but I don't know of an alternative
|| !_interactionSystem.InRangeUnobstructed(args.User, args.Target.Value, || !_interactionSystem.InRangeUnobstructed(args.User, args.Target.Value,
SharedInteractionSystem.MaxRaycastRange, CollisionGroup.Opaque)) SharedInteractionSystem.MaxRaycastRange, CollisionGroup.Opaque))
{
return; return;
}
args.Handled = true; args.Handled = true;
@@ -74,8 +81,10 @@ namespace Content.Server.Remotes
return; return;
} }
if (TryComp<AccessReaderComponent>(args.Target, out var accessComponent) && // Holding the door remote grants you access to the relevant doors IN ADDITION to what ever access you had.
!_doorSystem.HasAccess(args.Target.Value, args.Used, doorComp, accessComponent)) // This access is enforced in _doorSystem.HasAccess when it calls _accessReaderSystem.IsAllowed
if (TryComp<AccessReaderComponent>(args.Target, out var accessComponent)
&& !_doorSystem.HasAccess(args.Target.Value, args.User, doorComp, accessComponent))
{ {
_doorSystem.Deny(args.Target.Value, doorComp, args.User); _doorSystem.Deny(args.Target.Value, doorComp, args.User);
ShowPopupToUser("door-remote-denied", args.User); ShowPopupToUser("door-remote-denied", args.User);
@@ -85,7 +94,10 @@ namespace Content.Server.Remotes
switch (component.Mode) switch (component.Mode)
{ {
case OperatingMode.OpenClose: case OperatingMode.OpenClose:
if (_doorSystem.TryToggleDoor(args.Target.Value, doorComp, args.Used)) // Note we provide args.User here to TryToggleDoor as the "user"
// This means that the door will look at all access items carryed by the player for access, including
// this remote, but also including anything else they are carrying such as a PDA or ID card.
if (_doorSystem.TryToggleDoor(args.Target.Value, doorComp, args.User))
_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:
@@ -99,8 +111,12 @@ namespace Content.Server.Remotes
} }
break; break;
case OperatingMode.ToggleEmergencyAccess: case OperatingMode.ToggleEmergencyAccess:
if (airlockComp != null)
{
_airlock.ToggleEmergencyAccess(args.Target.Value, airlockComp); _airlock.ToggleEmergencyAccess(args.Target.Value, airlockComp);
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to set emergency access {(airlockComp.EmergencyAccess ? "on" : "off")}"); _adminLogger.Add(LogType.Action, LogImpact.Medium,
$"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to set emergency access {(airlockComp.EmergencyAccess ? "on" : "off")}");
}
break; break;
default: default:
throw new InvalidOperationException( throw new InvalidOperationException(

View File

@@ -21,6 +21,7 @@ namespace Content.Shared.Doors
/// </summary> /// </summary>
public sealed class BeforeDoorOpenedEvent : CancellableEntityEventArgs public sealed class BeforeDoorOpenedEvent : CancellableEntityEventArgs
{ {
public EntityUid? User = null;
} }
/// <summary> /// <summary>

View File

@@ -8,7 +8,7 @@ public abstract class SharedDoorBoltSystem : EntitySystem
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
[Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!;
[Dependency] private readonly SharedPopupSystem Popup = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();

View File

@@ -249,7 +249,7 @@ public abstract class SharedDoorSystem : EntitySystem
if (door.State == DoorState.Welded) if (door.State == DoorState.Welded)
return false; return false;
var ev = new BeforeDoorOpenedEvent(); var ev = new BeforeDoorOpenedEvent(){User=user};
RaiseLocalEvent(uid, ev, false); RaiseLocalEvent(uid, ev, false);
if (ev.Cancelled) if (ev.Cancelled)
return false; return false;
@@ -496,10 +496,10 @@ public abstract class SharedDoorSystem : EntitySystem
if (TryComp<AirlockComponent>(uid, out var airlock) && airlock.EmergencyAccess) if (TryComp<AirlockComponent>(uid, out var airlock) && airlock.EmergencyAccess)
return true; return true;
// Can't click to close firelocks. // Anyone can click to open firelocks
if (Resolve(uid, ref door) && door.State == DoorState.Open && if (Resolve(uid, ref door) && door.State == DoorState.Closed &&
TryComp<FirelockComponent>(uid, out var firelock)) TryComp<FirelockComponent>(uid, out var firelock))
return false; return true;
if (!Resolve(uid, ref access, false)) if (!Resolve(uid, ref access, false))
return true; return true;

View File

@@ -89,6 +89,7 @@
- id: GasAnalyzer - id: GasAnalyzer
- id: MedkitOxygenFilled - id: MedkitOxygenFilled
- id: HolofanProjector - id: HolofanProjector
- id: DoorRemoteFirefight
- type: entity - type: entity
id: LockerAtmosphericsFilled id: LockerAtmosphericsFilled

View File

@@ -138,6 +138,24 @@
groups: groups:
- Engineering - Engineering
- type: entity
parent: DoorRemoteDefault
id: DoorRemoteFirefight
name: fire-fighting door remote
description: A gadget which can open and bolt FireDoors remotely.
components:
- type: Sprite
layers:
- state: door_remotebase
- state: door_remotelightscolour
color: "#ff9900"
- state: door_remotescreencolour
color: "#e02020"
- type: Access
groups:
- Engineering
- type: entity - type: entity
parent: DoorRemoteDefault parent: DoorRemoteDefault
id: DoorRemoteAll id: DoorRemoteAll

View File

@@ -104,6 +104,9 @@
arc: 360 arc: 360
- type: StaticPrice - type: StaticPrice
price: 150 price: 150
- type: DoorBolt
- type: AccessReader
access: [ [ "Engineering" ] ]
- type: entity - type: entity
id: Firelock id: Firelock