diff --git a/Content.Client/GameObjects/Components/Doors/AirlockVisualizer.cs b/Content.Client/GameObjects/Components/Doors/AirlockVisualizer.cs
index 622e9d0c23..8501122b59 100644
--- a/Content.Client/GameObjects/Components/Doors/AirlockVisualizer.cs
+++ b/Content.Client/GameObjects/Components/Doors/AirlockVisualizer.cs
@@ -2,6 +2,7 @@
using Content.Client.GameObjects.Components.Wires;
using Content.Shared.Audio;
using Content.Shared.GameObjects.Components.Doors;
+using JetBrains.Annotations;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.Components.Animations;
@@ -12,6 +13,7 @@ using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Doors
{
+ [UsedImplicitly]
public class AirlockVisualizer : AppearanceVisualizer
{
private const string AnimationKey = "airlock_animation";
@@ -24,11 +26,17 @@ namespace Content.Client.GameObjects.Components.Doors
{
base.LoadData(node);
+ var delay = 0.8f;
+
var openSound = node.GetNode("open_sound").AsString();
var closeSound = node.GetNode("close_sound").AsString();
var denySound = node.GetNode("deny_sound").AsString();
+ if (node.TryGetNode("animation_time", out var yamlNode))
+ {
+ delay = yamlNode.AsFloat();
+ }
- CloseAnimation = new Animation {Length = TimeSpan.FromSeconds(0.8f)};
+ CloseAnimation = new Animation {Length = TimeSpan.FromSeconds(delay)};
{
var flick = new AnimationTrackSpriteFlick();
CloseAnimation.AnimationTracks.Add(flick);
@@ -50,7 +58,7 @@ namespace Content.Client.GameObjects.Components.Doors
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(closeSound, 0));
}
- OpenAnimation = new Animation {Length = TimeSpan.FromSeconds(0.8f)};
+ OpenAnimation = new Animation {Length = TimeSpan.FromSeconds(delay)};
{
var flick = new AnimationTrackSpriteFlick();
OpenAnimation.AnimationTracks.Add(flick);
diff --git a/Content.Server/Atmos/IGridAtmosphereComponent.cs b/Content.Server/Atmos/IGridAtmosphereComponent.cs
index 5518881767..fd5648c091 100644
--- a/Content.Server/Atmos/IGridAtmosphereComponent.cs
+++ b/Content.Server/Atmos/IGridAtmosphereComponent.cs
@@ -45,6 +45,12 @@ namespace Content.Server.Atmos
///
void FixVacuum(MapIndices indices);
+ ///
+ /// Revalidates indices immediately.
+ ///
+ ///
+ void Revalidate(MapIndices indices);
+
///
/// Adds an active tile so it becomes processed every update until it becomes inactive.
/// Also makes the tile excited.
diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs
index b1ad2df3cf..10ff57c948 100644
--- a/Content.Server/Atmos/TileAtmosphere.cs
+++ b/Content.Server/Atmos/TileAtmosphere.cs
@@ -1051,6 +1051,25 @@ namespace Content.Server.Atmos
private void ConsiderFirelocks(TileAtmosphere other)
{
// TODO ATMOS firelocks!
+ var reconsiderAdjacent = false;
+
+ foreach (var entity in GridIndices.GetEntitiesInTile(GridIndex))
+ {
+ if (!entity.TryGetComponent(out FirelockComponent firelock)) continue;
+ reconsiderAdjacent |= firelock.EmergencyPressureStop();
+ }
+
+ foreach (var entity in other.GridIndices.GetEntitiesInTile(other.GridIndex))
+ {
+ if (!entity.TryGetComponent(out FirelockComponent firelock)) continue;
+ reconsiderAdjacent |= firelock.EmergencyPressureStop();
+ }
+
+ if (reconsiderAdjacent)
+ {
+ UpdateAdjacent();
+ other.UpdateAdjacent();
+ }
}
private void React()
diff --git a/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs b/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs
index 07c6ed66e9..0d71d0717d 100644
--- a/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs
+++ b/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs
@@ -28,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Atmos
set
{
_airBlocked = value;
- EntitySystem.Get().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(_snapGrid.Position);
+ EntitySystem.Get().GetGridAtmosphere(Owner.Transform.GridID)?.Revalidate(_snapGrid.Position);
}
}
diff --git a/Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs b/Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs
new file mode 100644
index 0000000000..02d3ac22a5
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs
@@ -0,0 +1,85 @@
+using System.Threading.Tasks;
+using Content.Server.GameObjects.Components.Doors;
+using Content.Server.GameObjects.Components.Interactable;
+using Content.Shared.GameObjects.Components.Doors;
+using Content.Shared.GameObjects.Components.Interactable;
+using Content.Shared.Interfaces.GameObjects.Components;
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameObjects.Components;
+using Robust.Shared.Interfaces.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Atmos
+{
+ [RegisterComponent]
+ public class FirelockComponent : ServerDoorComponent, IInteractUsing, IActivate, ICollideBehavior
+ {
+ public override string Name => "Firelock";
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ }
+
+ public void CollideWith(IEntity collidedWith)
+ {
+ // We do nothing.
+ }
+
+ public void Activate(ActivateEventArgs eventArgs)
+ {
+ // We do nothing.
+ }
+
+ protected override void Startup()
+ {
+ base.Startup();
+
+ var airtightComponent = Owner.EnsureComponent();
+ var collidableComponent = Owner.GetComponent();
+
+ Safety = false;
+ airtightComponent.AirBlocked = false;
+ collidableComponent.Hard = false;
+
+ if (Occludes && Owner.TryGetComponent(out OccluderComponent occluder))
+ {
+ occluder.Enabled = false;
+ }
+
+ State = DoorState.Open;
+ SetAppearance(DoorVisualState.Open);
+ }
+
+ public bool EmergencyPressureStop()
+ {
+ var closed = State == DoorState.Open && Close();
+
+ if(closed)
+ Owner.GetComponent().AirBlocked = true;
+
+ return closed;
+ }
+
+ public override void Deny()
+ {
+ }
+
+ public override bool CanClose(IEntity user) => true;
+ public override bool CanOpen(IEntity user) => true;
+
+ public async Task InteractUsing(InteractUsingEventArgs eventArgs)
+ {
+ if (!eventArgs.Using.TryGetComponent(out var tool))
+ return false;
+
+ if (!await tool.UseTool(eventArgs.User, Owner, 3f, ToolQuality.Prying)) return false;
+
+ if (State == DoorState.Closed)
+ Open();
+ else if (State == DoorState.Open)
+ Close();
+
+ return true;
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs b/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs
index 05ba999b0b..9948bdba90 100644
--- a/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs
+++ b/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs
@@ -147,55 +147,62 @@ namespace Content.Server.GameObjects.Components.Atmos
{
foreach (var indices in _invalidatedCoords.ToArray())
{
- var tile = GetTile(indices);
- AddActiveTile(tile);
-
- if (tile == null)
- {
- tile = new TileAtmosphere(this, _grid.Index, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C});
- _tiles[indices] = tile;
- }
-
- if (IsSpace(indices))
- {
- tile.Air = new GasMixture(GetVolumeForCells(1));
- tile.Air.MarkImmutable();
- _tiles[indices] = tile;
-
- } else if (IsAirBlocked(indices))
- {
- tile.Air = null;
- }
- else
- {
- var obs = GetObstructingComponent(indices);
-
- if (obs != null)
- {
- if (tile.Air == null && obs.FixVacuum)
- {
- FixVacuum(tile.GridIndices);
- }
- }
-
- tile.Air ??= new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
- }
-
- tile.UpdateAdjacent();
- tile.UpdateVisuals();
-
- foreach (var direction in Cardinal)
- {
- var otherIndices = indices.Offset(direction);
- var otherTile = GetTile(otherIndices);
- AddActiveTile(otherTile);
- otherTile?.UpdateAdjacent(direction.GetOpposite());
- }
+ Revalidate(indices);
}
_invalidatedCoords.Clear();
}
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Revalidate(MapIndices indices)
+ {
+ var tile = GetTile(indices);
+ AddActiveTile(tile);
+
+ if (tile == null)
+ {
+ tile = new TileAtmosphere(this, _grid.Index, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C});
+ _tiles[indices] = tile;
+ }
+
+ if (IsSpace(indices))
+ {
+ tile.Air = new GasMixture(GetVolumeForCells(1));
+ tile.Air.MarkImmutable();
+ _tiles[indices] = tile;
+
+ } else if (IsAirBlocked(indices))
+ {
+ tile.Air = null;
+ }
+ else
+ {
+ var obs = GetObstructingComponent(indices);
+
+ if (obs != null)
+ {
+ if (tile.Air == null && obs.FixVacuum)
+ {
+ FixVacuum(tile.GridIndices);
+ }
+ }
+
+ tile.Air ??= new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
+ }
+
+ tile.UpdateAdjacent();
+ tile.UpdateVisuals();
+
+ foreach (var direction in Cardinal)
+ {
+ var otherIndices = indices.Offset(direction);
+ var otherTile = GetTile(otherIndices);
+ AddActiveTile(otherTile);
+ otherTile?.UpdateAdjacent(direction.GetOpposite());
+ }
+ }
+
///
public void FixVacuum(MapIndices indices)
{
diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
index ba2bc39377..381f276bd0 100644
--- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
+++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
@@ -61,6 +61,8 @@ namespace Content.Server.GameObjects.Components.Doors
[ViewVariables] private bool _occludes;
+ public bool Occludes => _occludes;
+
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
@@ -133,7 +135,7 @@ namespace Content.Server.GameObjects.Components.Doors
}
}
- private void SetAppearance(DoorVisualState state)
+ protected void SetAppearance(DoorVisualState state)
{
if (_appearance != null || Owner.TryGetComponent(out _appearance))
_appearance.SetData(DoorVisuals.VisualState, state);
@@ -144,7 +146,7 @@ namespace Content.Server.GameObjects.Components.Doors
return true;
}
- public bool CanOpen(IEntity user)
+ public virtual bool CanOpen(IEntity user)
{
if (!CanOpen()) return false;
if (!Owner.TryGetComponent(out AccessReader accessReader))
@@ -205,7 +207,7 @@ namespace Content.Server.GameObjects.Components.Doors
return true;
}
- public bool CanClose(IEntity user)
+ public virtual bool CanClose(IEntity user)
{
if (!CanClose()) return false;
if (!Owner.TryGetComponent(out AccessReader accessReader))
diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs
index b02472cfa5..1b1a8695f8 100644
--- a/Content.Shared/Maps/TurfHelpers.cs
+++ b/Content.Shared/Maps/TurfHelpers.cs
@@ -1,5 +1,7 @@
#nullable enable
using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
using Content.Shared.Physics;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
@@ -62,6 +64,7 @@ namespace Content.Shared.Maps
///
/// Helper that returns all entities in a turf.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IEnumerable GetEntitiesInTile(this TileRef turf, bool approximate = false)
{
var entityManager = IoCManager.Resolve();
@@ -69,6 +72,32 @@ namespace Content.Shared.Maps
return entityManager.GetEntitiesIntersecting(turf.MapIndex, GetWorldTileBox(turf), approximate);
}
+ ///
+ /// Helper that returns all entities in a turf.
+ ///
+ public static IEnumerable GetEntitiesInTile(this GridCoordinates coordinates, bool approximate = false)
+ {
+ var turf = coordinates.GetTileRef();
+
+ if (turf == null)
+ return Enumerable.Empty();
+
+ return GetEntitiesInTile(turf.Value);
+ }
+
+ ///
+ /// Helper that returns all entities in a turf.
+ ///
+ public static IEnumerable GetEntitiesInTile(this MapIndices indices, GridId gridId, bool approximate = false)
+ {
+ var turf = indices.GetTileRef(gridId);
+
+ if (turf == null)
+ return Enumerable.Empty();
+
+ return GetEntitiesInTile(turf.Value);
+ }
+
///
/// Checks if a turf has something dense on it.
///
diff --git a/Resources/Prototypes/Entities/Constructible/Doors/airlock_base.yml b/Resources/Prototypes/Entities/Constructible/Doors/airlock_base.yml
index ad88ad239f..8383ee0575 100644
--- a/Resources/Prototypes/Entities/Constructible/Doors/airlock_base.yml
+++ b/Resources/Prototypes/Entities/Constructible/Doors/airlock_base.yml
@@ -54,7 +54,6 @@
type: WiresBoundUserInterface
- type: Airtight
fixVacuum: true
- adjacentAtmosphere: true
- type: Occluder
- type: SnapGrid
offset: Center
diff --git a/Resources/Prototypes/Entities/Constructible/Doors/firelock.yml b/Resources/Prototypes/Entities/Constructible/Doors/firelock.yml
new file mode 100644
index 0000000000..ecfe8b2578
--- /dev/null
+++ b/Resources/Prototypes/Entities/Constructible/Doors/firelock.yml
@@ -0,0 +1,74 @@
+- type: entity
+ id: Firelock
+ name: firelock
+ description: Apply crowbar.
+ components:
+ - type: Clickable
+ - type: InteractionOutline
+ - type: Sprite
+ netsync: false
+ drawdepth: Mobs # They're on the same layer as mobs, perspective.
+ sprite: Constructible/Structures/Doors/firelock.rsi
+ layers:
+ - state: closed
+ map: ["enum.DoorVisualLayers.Base"]
+ - state: closed_unlit
+ shader: unshaded
+ map: ["enum.DoorVisualLayers.BaseUnlit"]
+ - state: bolted
+ shader: unshaded
+ map: ["enum.DoorVisualLayers.BaseBolted"]
+ - state: panel_open
+ map: ["enum.WiresVisualLayers.MaintenancePanel"]
+ - type: Icon
+ sprite: Constructible/Structures/Doors/firelock.rsi
+ state: closed
+ - type: Collidable
+ shapes:
+ - !type:PhysShapeAabb
+ bounds: "-0.49,-0.49,0.49,0.49" # don't want this colliding with walls or they won't close
+ mask:
+ - MobImpassable
+ layer:
+ - Opaque
+ - Impassable
+ - MobImpassable
+ - VaultImpassable
+ - SmallImpassable
+ - type: Firelock
+ - type: Appearance
+ visuals:
+ - type: AirlockVisualizer
+ open_sound: /Audio/Machines/airlock_open.ogg
+ close_sound: /Audio/Machines/airlock_close.ogg
+ deny_sound: /Audio/Machines/airlock_deny.ogg
+ animation_time: 0.6
+ - type: WiresVisualizer
+ - type: Wires
+ BoardName: "Firelock Control"
+ LayoutId: Firelock
+ - type: UserInterface
+ interfaces:
+ - key: enum.WiresUiKey.Key
+ type: WiresBoundUserInterface
+ - type: Airtight
+ fixVacuum: true
+ - type: Occluder
+ - type: SnapGrid
+ offset: Center
+ placement:
+ mode: SnapgridCenter
+
+- type: entity
+ id: FirelockGlass
+ parent: Firelock
+ name: glass firelock
+ components:
+ - type: Firelock
+ occludes: false
+ - type: Occluder
+ enabled: false
+ - type: Sprite
+ sprite: Constructible/Structures/Doors/firelock_glass.rsi
+ - type: Icon
+ sprite: Constructible/Structures/Doors/firelock_glass.rsi
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/closed.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/closed.png
new file mode 100644
index 0000000000..8c90b693a4
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/closed.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/closing.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/closing.png
new file mode 100644
index 0000000000..b035acbb18
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/closing.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/deny.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/deny.png
new file mode 100644
index 0000000000..dd3332927c
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/deny.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame1.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame1.png
new file mode 100644
index 0000000000..458698515f
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame1.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame2.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame2.png
new file mode 100644
index 0000000000..67f782bd89
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame2.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame3.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame3.png
new file mode 100644
index 0000000000..5421154834
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame3.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame4.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame4.png
new file mode 100644
index 0000000000..6252d37d1e
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/frame4.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/locked.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/locked.png
new file mode 100644
index 0000000000..3b02d55571
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/locked.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/meta.json b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/meta.json
new file mode 100644
index 0000000000..c25c825232
--- /dev/null
+++ b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/meta.json
@@ -0,0 +1,170 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "CC-BY-SA 3.0",
+ "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd",
+ "states": [
+ {
+ "name": "closed",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "closing",
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "deny",
+ "directions": 1,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "frame1",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "frame2",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "frame3",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "frame4",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "locked",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "open",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "opening",
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "panel_closing",
+ "directions": 1,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.27
+ ]
+ ]
+ },
+ {
+ "name": "panel_open",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "panel_opening",
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "welded",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "welded_open",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/open.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/open.png
new file mode 100644
index 0000000000..a89b493a8b
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/open.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/opening.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/opening.png
new file mode 100644
index 0000000000..a20b3e4503
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/opening.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_closing.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_closing.png
new file mode 100644
index 0000000000..ae69b8aded
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_closing.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_open.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_open.png
new file mode 100644
index 0000000000..5f3bfeae15
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_open.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_opening.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_opening.png
new file mode 100644
index 0000000000..8271b80b11
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/panel_opening.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/welded.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/welded.png
new file mode 100644
index 0000000000..54de288e54
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/welded.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/welded_open.png b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/welded_open.png
new file mode 100644
index 0000000000..d5b1d509b5
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock.rsi/welded_open.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/closed.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/closed.png
new file mode 100644
index 0000000000..602b83df5b
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/closed.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/closing.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/closing.png
new file mode 100644
index 0000000000..6718ae08e9
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/closing.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/deny.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/deny.png
new file mode 100644
index 0000000000..a2b151c140
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/deny.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/locked.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/locked.png
new file mode 100644
index 0000000000..5c87415ec1
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/locked.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/meta.json b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/meta.json
new file mode 100644
index 0000000000..817344977f
--- /dev/null
+++ b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/meta.json
@@ -0,0 +1,134 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "CC-BY-SA 3.0",
+ "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd",
+ "states": [
+ {
+ "name": "closed",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "closing",
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "deny",
+ "directions": 1,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "locked",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "open",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "opening",
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "panel_closing",
+ "directions": 1,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.27
+ ]
+ ]
+ },
+ {
+ "name": "panel_open",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "panel_opening",
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.07,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "welded",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "welded_open",
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/open.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/open.png
new file mode 100644
index 0000000000..6fcb5b059b
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/open.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/opening.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/opening.png
new file mode 100644
index 0000000000..113ddab7b7
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/opening.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_closing.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_closing.png
new file mode 100644
index 0000000000..ae69b8aded
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_closing.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_open.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_open.png
new file mode 100644
index 0000000000..5f3bfeae15
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_open.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_opening.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_opening.png
new file mode 100644
index 0000000000..8271b80b11
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/panel_opening.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/welded.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/welded.png
new file mode 100644
index 0000000000..c44b529664
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/welded.png differ
diff --git a/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/welded_open.png b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/welded_open.png
new file mode 100644
index 0000000000..f13079c8db
Binary files /dev/null and b/Resources/Textures/Constructible/Structures/Doors/firelock_glass.rsi/welded_open.png differ
diff --git a/RobustToolbox b/RobustToolbox
index c72ea7194e..1513389fc1 160000
--- a/RobustToolbox
+++ b/RobustToolbox
@@ -1 +1 @@
-Subproject commit c72ea7194e08bba42371a06e353bcd79f5a7c7cc
+Subproject commit 1513389fc195442a0f08b0af488a25affb33d410
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 9a0e2799ef..c9b97a94bc 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -51,6 +51,7 @@
<data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
True
True
+ True
True
True
True