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
{
[Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!;
[Dependency] protected readonly SharedAppearanceSystem _appearanceSystem = default!;
public override void Initialize()
{
@@ -18,10 +18,23 @@ public sealed class FirelockSystem : EntitySystem
if (args.Sprite == null)
return;
// Apply the closed lights bool to the sprite
bool unlitVisible =
(AppearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) &&
closedLights);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible);
var boltedVisible = false;
var unlitVisible = false;
if (!_appearanceSystem.TryGetData<DoorState>(uid, DoorVisuals.State, out var state, args.Component))
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.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Remotes;
using Content.Server.Shuttles.Components;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Doors;
@@ -25,6 +28,7 @@ namespace Content.Server.Doors.Systems
[Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
private static float _visualUpdateInterval = 0.5f;
private float _accumulatedFrameTime;
@@ -133,7 +137,10 @@ namespace Content.Server.Doors.Systems
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();
}

View File

@@ -39,10 +39,14 @@ namespace Content.Server.Remotes
component.Mode = OperatingMode.ToggleBolts;
switchMessageId = "door-remote-switch-state-toggle-bolts";
break;
// Skip toggle bolts mode and move on from there (to emergency access)
case OperatingMode.ToggleBolts:
component.Mode = OperatingMode.ToggleEmergencyAccess;
switchMessageId = "door-remote-switch-state-toggle-emergency-access";
break;
// Skip ToggleEmergencyAccess mode and move on from there (to door toggle)
case OperatingMode.ToggleEmergencyAccess:
component.Mode = OperatingMode.OpenClose;
switchMessageId = "door-remote-switch-state-open-close";
@@ -56,15 +60,18 @@ namespace Content.Server.Remotes
private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, BeforeRangedInteractEvent args)
{
bool isAirlock = TryComp<AirlockComponent>(args.Target, out var airlockComp);
if (args.Handled
|| args.Target == null
|| !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.
// This doesn't work that well, but I don't know of an alternative
|| !_interactionSystem.InRangeUnobstructed(args.User, args.Target.Value,
SharedInteractionSystem.MaxRaycastRange, CollisionGroup.Opaque))
{
return;
}
args.Handled = true;
@@ -74,8 +81,10 @@ namespace Content.Server.Remotes
return;
}
if (TryComp<AccessReaderComponent>(args.Target, out var accessComponent) &&
!_doorSystem.HasAccess(args.Target.Value, args.Used, doorComp, accessComponent))
// Holding the door remote grants you access to the relevant doors IN ADDITION to what ever access you had.
// 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);
ShowPopupToUser("door-remote-denied", args.User);
@@ -85,7 +94,10 @@ namespace Content.Server.Remotes
switch (component.Mode)
{
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}");
break;
case OperatingMode.ToggleBolts:
@@ -99,8 +111,12 @@ namespace Content.Server.Remotes
}
break;
case OperatingMode.ToggleEmergencyAccess:
_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")}");
if (airlockComp != null)
{
_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")}");
}
break;
default:
throw new InvalidOperationException(

View File

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

View File

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

View File

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

View File

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

View File

@@ -138,6 +138,24 @@
groups:
- 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
parent: DoorRemoteDefault
id: DoorRemoteAll

View File

@@ -1,94 +1,94 @@
- type: entity
id: HighSecDoor
parent: BaseStructure
name: high security door
description: Keeps the bad out and keeps the good in.
placement:
mode: SnapgridCenter
components:
- type: InteractionOutline
- type: Sprite
sprite: Structures/Doors/Airlocks/highsec/highsec.rsi
layers:
- state: closed
map: ["enum.DoorVisualLayers.Base"]
- state: closed_unlit
shader: unshaded
map: ["enum.DoorVisualLayers.BaseUnlit"]
- state: welded
map: ["enum.WeldableLayers.BaseWelded"]
- state: bolted_unlit
shader: unshaded
map: ["enum.DoorVisualLayers.BaseBolted"]
- state: emergency_unlit
map: ["enum.DoorVisualLayers.BaseEmergencyAccess"]
shader: unshaded
- state: panel_open
map: ["enum.WiresVisualLayers.MaintenancePanel"]
- type: AnimationPlayer
- type: Physics
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeAabb
bounds: "-0.49,-0.49,0.49,0.49" # don't want this colliding with walls or they won't close
density: 100
mask:
- FullTileMask
layer:
- WallLayer
- type: ContainerFill
containers:
board: [ DoorElectronics ]
- type: ContainerContainer
containers:
board: !type:Container
- type: Door
crushDamage:
types:
Blunt: 50
openSound:
path: /Audio/Machines/airlock_open.ogg
closeSound:
path: /Audio/Machines/airlock_close.ogg
denySound:
path: /Audio/Machines/airlock_deny.ogg
- type: Weldable
time: 10
- type: Airlock
- type: DoorBolt
- type: Appearance
- type: WiresVisuals
- type: ApcPowerReceiver
powerLoad: 20
- type: ExtensionCableReceiver
- type: Electrified
enabled: false
usesApcPower: true
- type: WiresPanel
- type: Wires
BoardName: "HighSec Control"
LayoutId: HighSec
alwaysRandomize: true
- type: UserInterface
interfaces:
- key: enum.WiresUiKey.Key
type: WiresBoundUserInterface
- type: Airtight
fixVacuum: true
- type: Occluder
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 1500
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: IconSmooth
key: walls
mode: NoSprite
- type: entity
id: HighSecDoor
parent: BaseStructure
name: high security door
description: Keeps the bad out and keeps the good in.
placement:
mode: SnapgridCenter
components:
- type: InteractionOutline
- type: Sprite
sprite: Structures/Doors/Airlocks/highsec/highsec.rsi
layers:
- state: closed
map: ["enum.DoorVisualLayers.Base"]
- state: closed_unlit
shader: unshaded
map: ["enum.DoorVisualLayers.BaseUnlit"]
- state: welded
map: ["enum.WeldableLayers.BaseWelded"]
- state: bolted_unlit
shader: unshaded
map: ["enum.DoorVisualLayers.BaseBolted"]
- state: emergency_unlit
map: ["enum.DoorVisualLayers.BaseEmergencyAccess"]
shader: unshaded
- state: panel_open
map: ["enum.WiresVisualLayers.MaintenancePanel"]
- type: AnimationPlayer
- type: Physics
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeAabb
bounds: "-0.49,-0.49,0.49,0.49" # don't want this colliding with walls or they won't close
density: 100
mask:
- FullTileMask
layer:
- WallLayer
- type: ContainerFill
containers:
board: [ DoorElectronics ]
- type: ContainerContainer
containers:
board: !type:Container
- type: Door
crushDamage:
types:
Blunt: 50
openSound:
path: /Audio/Machines/airlock_open.ogg
closeSound:
path: /Audio/Machines/airlock_close.ogg
denySound:
path: /Audio/Machines/airlock_deny.ogg
- type: Weldable
time: 10
- type: Airlock
- type: DoorBolt
- type: Appearance
- type: WiresVisuals
- type: ApcPowerReceiver
powerLoad: 20
- type: ExtensionCableReceiver
- type: Electrified
enabled: false
usesApcPower: true
- type: WiresPanel
- type: Wires
BoardName: "HighSec Control"
LayoutId: HighSec
alwaysRandomize: true
- type: UserInterface
interfaces:
- key: enum.WiresUiKey.Key
type: WiresBoundUserInterface
- type: Airtight
fixVacuum: true
- type: Occluder
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 1500
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: IconSmooth
key: walls
mode: NoSprite

View File

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