Firelocks and atmos optimizations (#2029)
* Some work * unlit layers for firelock.rsi * firelock stuff I guess * changes dunno * Support for non-fulltile firelocks! * Fix TurfHelpers * Replace GridCoordinates (ew) for EntityCoordinates (YAY) * whoops * Fix firelocks * fix glass firelocks * Big optimizations * Optimize even further * Support for non-fulltile airblockers rotating * whoops. * Adds edge firelocks * Fix atmos bug with gasmixture serialization * Redundant adjacent update * ignored components * Add gas mixture tests * new test case for removeratio test * Apply suggestions from code review Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com> * address all reviews Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
@@ -2,6 +2,7 @@
|
|||||||
using Content.Client.GameObjects.Components.Wires;
|
using Content.Client.GameObjects.Components.Wires;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.GameObjects.Components.Doors;
|
using Content.Shared.GameObjects.Components.Doors;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.GameObjects.Components.Animations;
|
using Robust.Client.GameObjects.Components.Animations;
|
||||||
@@ -12,6 +13,7 @@ using YamlDotNet.RepresentationModel;
|
|||||||
|
|
||||||
namespace Content.Client.GameObjects.Components.Doors
|
namespace Content.Client.GameObjects.Components.Doors
|
||||||
{
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
public class AirlockVisualizer : AppearanceVisualizer
|
public class AirlockVisualizer : AppearanceVisualizer
|
||||||
{
|
{
|
||||||
private const string AnimationKey = "airlock_animation";
|
private const string AnimationKey = "airlock_animation";
|
||||||
@@ -24,11 +26,17 @@ namespace Content.Client.GameObjects.Components.Doors
|
|||||||
{
|
{
|
||||||
base.LoadData(node);
|
base.LoadData(node);
|
||||||
|
|
||||||
|
var delay = 0.8f;
|
||||||
|
|
||||||
var openSound = node.GetNode("open_sound").AsString();
|
var openSound = node.GetNode("open_sound").AsString();
|
||||||
var closeSound = node.GetNode("close_sound").AsString();
|
var closeSound = node.GetNode("close_sound").AsString();
|
||||||
var denySound = node.GetNode("deny_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();
|
var flick = new AnimationTrackSpriteFlick();
|
||||||
CloseAnimation.AnimationTracks.Add(flick);
|
CloseAnimation.AnimationTracks.Add(flick);
|
||||||
@@ -50,7 +58,7 @@ namespace Content.Client.GameObjects.Components.Doors
|
|||||||
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(closeSound, 0));
|
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();
|
var flick = new AnimationTrackSpriteFlick();
|
||||||
OpenAnimation.AnimationTracks.Add(flick);
|
OpenAnimation.AnimationTracks.Add(flick);
|
||||||
|
|||||||
@@ -176,6 +176,7 @@
|
|||||||
"ExtinguisherCabinet",
|
"ExtinguisherCabinet",
|
||||||
"ExtinguisherCabinetFilled",
|
"ExtinguisherCabinetFilled",
|
||||||
"FireExtinguisher",
|
"FireExtinguisher",
|
||||||
|
"Firelock",
|
||||||
"AtmosPlaque",
|
"AtmosPlaque",
|
||||||
"Spillable",
|
"Spillable",
|
||||||
};
|
};
|
||||||
|
|||||||
85
Content.IntegrationTests/Tests/Atmos/GasMixtureTest.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Atmos;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Atmos
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
[TestOf(typeof(GasMixture))]
|
||||||
|
public class GasMixtureTest : ContentIntegrationTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task TestMerge()
|
||||||
|
{
|
||||||
|
var server = StartServerDummyTicker();
|
||||||
|
|
||||||
|
server.Assert(() =>
|
||||||
|
{
|
||||||
|
var a = new GasMixture(10f);
|
||||||
|
var b = new GasMixture(10f);
|
||||||
|
|
||||||
|
a.AdjustMoles(Gas.Oxygen, 50);
|
||||||
|
b.AdjustMoles(Gas.Nitrogen, 50);
|
||||||
|
|
||||||
|
// a now has 50 moles of oxygen
|
||||||
|
Assert.That(a.TotalMoles, Is.EqualTo(50));
|
||||||
|
Assert.That(a.GetMoles(Gas.Oxygen), Is.EqualTo(50));
|
||||||
|
|
||||||
|
// b now has 50 moles of nitrogen
|
||||||
|
Assert.That(b.TotalMoles, Is.EqualTo(50));
|
||||||
|
Assert.That(b.GetMoles(Gas.Nitrogen), Is.EqualTo(50));
|
||||||
|
|
||||||
|
b.Merge(a);
|
||||||
|
|
||||||
|
// b now has its contents and the contents of a
|
||||||
|
Assert.That(b.TotalMoles, Is.EqualTo(100));
|
||||||
|
Assert.That(b.GetMoles(Gas.Oxygen), Is.EqualTo(50));
|
||||||
|
Assert.That(b.GetMoles(Gas.Nitrogen), Is.EqualTo(50));
|
||||||
|
|
||||||
|
// a should be the same, however.
|
||||||
|
Assert.That(a.TotalMoles, Is.EqualTo(50));
|
||||||
|
Assert.That(a.GetMoles(Gas.Oxygen), Is.EqualTo(50));
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0.5f)]
|
||||||
|
[TestCase(0.25f)]
|
||||||
|
[TestCase(0.75f)]
|
||||||
|
[TestCase(1f)]
|
||||||
|
[TestCase(0f)]
|
||||||
|
[TestCase(Atmospherics.BreathPercentage)]
|
||||||
|
public async Task RemoveRatio(float ratio)
|
||||||
|
{
|
||||||
|
var server = StartServerDummyTicker();
|
||||||
|
|
||||||
|
server.Assert(() =>
|
||||||
|
{
|
||||||
|
var a = new GasMixture(10f);
|
||||||
|
|
||||||
|
a.AdjustMoles(Gas.Oxygen, 100);
|
||||||
|
a.AdjustMoles(Gas.Nitrogen, 100);
|
||||||
|
|
||||||
|
var origTotal = a.TotalMoles;
|
||||||
|
|
||||||
|
// we remove moles from the mixture with a ratio.
|
||||||
|
var b = a.RemoveRatio(ratio);
|
||||||
|
|
||||||
|
// check that the amount of moles in the original and the new mixture are correct.
|
||||||
|
Assert.That(b.TotalMoles, Is.EqualTo(origTotal * ratio));
|
||||||
|
Assert.That(a.TotalMoles, Is.EqualTo(origTotal - b.TotalMoles));
|
||||||
|
|
||||||
|
Assert.That(b.GetMoles(Gas.Oxygen), Is.EqualTo(100 * ratio));
|
||||||
|
Assert.That(b.GetMoles(Gas.Nitrogen), Is.EqualTo(100 * ratio));
|
||||||
|
|
||||||
|
Assert.That(a.GetMoles(Gas.Oxygen), Is.EqualTo(100 - b.GetMoles(Gas.Oxygen)));
|
||||||
|
Assert.That(a.GetMoles(Gas.Nitrogen), Is.EqualTo(100 - b.GetMoles(Gas.Nitrogen)));
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -545,6 +545,10 @@ namespace Content.Server.Atmos
|
|||||||
serializer.DataField(ref _moles, "moles", new float[Atmospherics.TotalNumberOfGases]);
|
serializer.DataField(ref _moles, "moles", new float[Atmospherics.TotalNumberOfGases]);
|
||||||
serializer.DataField(ref _molesArchived, "molesArchived", new float[Atmospherics.TotalNumberOfGases]);
|
serializer.DataField(ref _molesArchived, "molesArchived", new float[Atmospherics.TotalNumberOfGases]);
|
||||||
serializer.DataField(ref _temperature, "temperature", Atmospherics.TCMB);
|
serializer.DataField(ref _temperature, "temperature", Atmospherics.TCMB);
|
||||||
|
|
||||||
|
// The arrays MUST have a specific length.
|
||||||
|
Array.Resize(ref _moles, Atmospherics.TotalNumberOfGases);
|
||||||
|
Array.Resize(ref _molesArchived, Atmospherics.TotalNumberOfGases);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
using Content.Server.GameObjects.Components.Atmos.Piping;
|
using Content.Server.GameObjects.Components.Atmos.Piping;
|
||||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
|
||||||
namespace Content.Server.Atmos
|
namespace Content.Server.Atmos
|
||||||
{
|
{
|
||||||
@@ -42,6 +45,12 @@ namespace Content.Server.Atmos
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void FixVacuum(MapIndices indices);
|
void FixVacuum(MapIndices indices);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Revalidates indices immediately.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indices"></param>
|
||||||
|
void UpdateAdjacentBits(MapIndices indices);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an active tile so it becomes processed every update until it becomes inactive.
|
/// Adds an active tile so it becomes processed every update until it becomes inactive.
|
||||||
/// Also makes the tile excited.
|
/// Also makes the tile excited.
|
||||||
@@ -109,6 +118,7 @@ namespace Content.Server.Atmos
|
|||||||
/// Returns a tile.
|
/// Returns a tile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="indices"></param>
|
/// <param name="indices"></param>
|
||||||
|
/// <param name="createSpace"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
TileAtmosphere GetTile(MapIndices indices, bool createSpace = true);
|
TileAtmosphere GetTile(MapIndices indices, bool createSpace = true);
|
||||||
|
|
||||||
@@ -116,17 +126,19 @@ namespace Content.Server.Atmos
|
|||||||
/// Returns a tile.
|
/// Returns a tile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="coordinates"></param>
|
/// <param name="coordinates"></param>
|
||||||
|
/// <param name="createSpace"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
TileAtmosphere GetTile(EntityCoordinates coordinates, bool createSpace = true);
|
TileAtmosphere GetTile(EntityCoordinates coordinates, bool createSpace = true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns if the tile in question is air-blocked.
|
/// Returns if the tile in question is air-blocked.
|
||||||
/// This could be due to a wall, an airlock, etc.
|
/// This could be due to a wall, an airlock, etc.
|
||||||
/// Also see AirtightComponent.
|
/// <seealso cref="AirtightComponent"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="indices"></param>
|
/// <param name="indices"></param>
|
||||||
|
/// <param name="direction"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool IsAirBlocked(MapIndices indices);
|
bool IsAirBlocked(MapIndices indices, AtmosDirection direction);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns if the tile in question is space.
|
/// Returns if the tile in question is space.
|
||||||
@@ -142,6 +154,11 @@ namespace Content.Server.Atmos
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
float GetVolumeForCells(int cellCount);
|
float GetVolumeForCells(int cellCount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a dictionary of adjacent TileAtmospheres.
|
||||||
|
/// </summary>
|
||||||
|
Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(MapIndices indices, bool includeAirBlocked = false);
|
||||||
|
|
||||||
void Update(float frameTime);
|
void Update(float frameTime);
|
||||||
|
|
||||||
void AddPipeNet(IPipeNet pipeNet);
|
void AddPipeNet(IPipeNet pipeNet);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Server.Atmos.Reactions;
|
|||||||
using Content.Server.GameObjects.Components.Atmos;
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
using Content.Server.GameObjects.EntitySystems.Atmos;
|
using Content.Server.GameObjects.EntitySystems.Atmos;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
|
using Content.Server.Utility;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
@@ -66,7 +67,7 @@ namespace Content.Server.Atmos
|
|||||||
public float HeatCapacity { get; set; } = 1f;
|
public float HeatCapacity { get; set; } = 1f;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public float ThermalConductivity => Tile?.Tile.GetContentTileDefinition().ThermalConductivity ?? 0.05f;
|
public float ThermalConductivity { get; set; } = 0.05f;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool Excited { get; set; }
|
public bool Excited { get; set; }
|
||||||
@@ -111,8 +112,13 @@ namespace Content.Server.Atmos
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public GasMixture Air { get; set; }
|
public GasMixture Air { get; set; }
|
||||||
|
|
||||||
|
[ViewVariables, UsedImplicitly]
|
||||||
|
private int _blockedAirflow => (int)BlockedAirflow;
|
||||||
|
|
||||||
|
public AtmosDirection BlockedAirflow { get; set; } = AtmosDirection.Invalid;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool BlocksAir => _gridAtmosphereComponent.IsAirBlocked(GridIndices);
|
public bool BlocksAllAir => BlockedAirflow == AtmosDirection.All;
|
||||||
|
|
||||||
public TileAtmosphere(GridAtmosphereComponent atmosphereComponent, GridId gridIndex, MapIndices gridIndices, GasMixture mixture = null, bool immutable = false)
|
public TileAtmosphere(GridAtmosphereComponent atmosphereComponent, GridId gridIndex, MapIndices gridIndices, GasMixture mixture = null, bool immutable = false)
|
||||||
{
|
{
|
||||||
@@ -867,12 +873,12 @@ namespace Content.Server.Atmos
|
|||||||
private void FinishSuperconduction()
|
private void FinishSuperconduction()
|
||||||
{
|
{
|
||||||
// Conduct with air on my tile if I have it
|
// Conduct with air on my tile if I have it
|
||||||
if (!BlocksAir)
|
if (!BlocksAllAir)
|
||||||
{
|
{
|
||||||
Temperature = Air.TemperatureShare(ThermalConductivity, Temperature, HeatCapacity);
|
Temperature = Air.TemperatureShare(ThermalConductivity, Temperature, HeatCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishSuperconduction(BlocksAir ? Temperature : Air.Temperature);
|
FinishSuperconduction(BlocksAllAir ? Temperature : Air.Temperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FinishSuperconduction(float temperature)
|
private void FinishSuperconduction(float temperature)
|
||||||
@@ -886,9 +892,9 @@ namespace Content.Server.Atmos
|
|||||||
|
|
||||||
private void NeighborConductWithSource(TileAtmosphere other)
|
private void NeighborConductWithSource(TileAtmosphere other)
|
||||||
{
|
{
|
||||||
if (BlocksAir)
|
if (BlocksAllAir)
|
||||||
{
|
{
|
||||||
if (!other.BlocksAir)
|
if (!other.BlocksAllAir)
|
||||||
{
|
{
|
||||||
other.TemperatureShareOpenToSolid(this);
|
other.TemperatureShareOpenToSolid(this);
|
||||||
}
|
}
|
||||||
@@ -901,7 +907,7 @@ namespace Content.Server.Atmos
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!other.BlocksAir)
|
if (!other.BlocksAllAir)
|
||||||
{
|
{
|
||||||
other.Air.TemperatureShare(Air, Atmospherics.WindowHeatTransferCoefficient);
|
other.Air.TemperatureShare(Air, Atmospherics.WindowHeatTransferCoefficient);
|
||||||
}
|
}
|
||||||
@@ -952,7 +958,7 @@ namespace Content.Server.Atmos
|
|||||||
|
|
||||||
public AtmosDirection ConductivityDirections()
|
public AtmosDirection ConductivityDirections()
|
||||||
{
|
{
|
||||||
if(BlocksAir)
|
if(BlocksAllAir)
|
||||||
{
|
{
|
||||||
if(_archivedCycle < _gridAtmosphereComponent.UpdateCounter)
|
if(_archivedCycle < _gridAtmosphereComponent.UpdateCounter)
|
||||||
Archive(_gridAtmosphereComponent.UpdateCounter);
|
Archive(_gridAtmosphereComponent.UpdateCounter);
|
||||||
@@ -1087,7 +1093,25 @@ namespace Content.Server.Atmos
|
|||||||
|
|
||||||
private void ConsiderFirelocks(TileAtmosphere other)
|
private void ConsiderFirelocks(TileAtmosphere other)
|
||||||
{
|
{
|
||||||
// TODO ATMOS firelocks!
|
var reconsiderAdjacent = false;
|
||||||
|
|
||||||
|
foreach (var entity in GridIndices.GetEntitiesInTileFast(GridIndex, _gridAtmosphereComponent.GridTileLookupSystem))
|
||||||
|
{
|
||||||
|
if (!entity.TryGetComponent(out FirelockComponent firelock)) continue;
|
||||||
|
reconsiderAdjacent |= firelock.EmergencyPressureStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entity in other.GridIndices.GetEntitiesInTileFast(other.GridIndex, _gridAtmosphereComponent.GridTileLookupSystem))
|
||||||
|
{
|
||||||
|
if (!entity.TryGetComponent(out FirelockComponent firelock)) continue;
|
||||||
|
reconsiderAdjacent |= firelock.EmergencyPressureStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reconsiderAdjacent)
|
||||||
|
{
|
||||||
|
UpdateAdjacent();
|
||||||
|
other.UpdateAdjacent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void React()
|
private void React()
|
||||||
@@ -1130,7 +1154,7 @@ namespace Content.Server.Atmos
|
|||||||
_adjacentTiles[direction.ToIndex()] = adjacent;
|
_adjacentTiles[direction.ToIndex()] = adjacent;
|
||||||
adjacent?.UpdateAdjacent(direction.GetOpposite());
|
adjacent?.UpdateAdjacent(direction.GetOpposite());
|
||||||
|
|
||||||
if (adjacent != null && !_gridAtmosphereComponent.IsAirBlocked(adjacent.GridIndices))
|
if (adjacent != null && !BlockedAirflow.HasFlag(direction) && !_gridAtmosphereComponent.IsAirBlocked(adjacent.GridIndices, direction.GetOpposite()))
|
||||||
{
|
{
|
||||||
_adjacentBits |= direction;
|
_adjacentBits |= direction;
|
||||||
}
|
}
|
||||||
@@ -1138,10 +1162,16 @@ namespace Content.Server.Atmos
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAdjacent(AtmosDirection direction)
|
public void UpdateAdjacent(AtmosDirection direction)
|
||||||
{
|
|
||||||
if (!_gridAtmosphereComponent.IsAirBlocked(GridIndices.Offset(direction.ToDirection())))
|
|
||||||
{
|
{
|
||||||
_adjacentTiles[direction.ToIndex()] = _gridAtmosphereComponent.GetTile(GridIndices.Offset(direction.ToDirection()));
|
_adjacentTiles[direction.ToIndex()] = _gridAtmosphereComponent.GetTile(GridIndices.Offset(direction.ToDirection()));
|
||||||
|
|
||||||
|
if (!BlockedAirflow.HasFlag(direction) && !_gridAtmosphereComponent.IsAirBlocked(GridIndices.Offset(direction.ToDirection()), direction.GetOpposite()))
|
||||||
|
{
|
||||||
|
_adjacentBits |= direction;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_adjacentBits &= ~direction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Components.Transform;
|
using Robust.Shared.GameObjects.Components.Transform;
|
||||||
@@ -9,6 +11,7 @@ using Robust.Shared.Interfaces.Map;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
@@ -21,12 +24,21 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
private (GridId, MapIndices) _lastPosition;
|
private (GridId, MapIndices) _lastPosition;
|
||||||
|
private AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
|
||||||
public override string Name => "Airtight";
|
public override string Name => "Airtight";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private int _airBlockedDirection;
|
||||||
private bool _airBlocked = true;
|
private bool _airBlocked = true;
|
||||||
private bool _fixVacuum = false;
|
private bool _fixVacuum = false;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _rotateAirBlocked = true;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _fixAirBlockedDirectionInitialize = true;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool AirBlocked
|
public bool AirBlocked
|
||||||
{
|
{
|
||||||
@@ -35,11 +47,19 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
{
|
{
|
||||||
_airBlocked = value;
|
_airBlocked = value;
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
|
UpdatePosition();
|
||||||
{
|
|
||||||
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(snapGrid.Position);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AtmosDirection AirBlockedDirection
|
||||||
|
{
|
||||||
|
get => (AtmosDirection)_airBlockedDirection;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_airBlockedDirection = (int) value;
|
||||||
|
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
@@ -51,22 +71,53 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
|
|
||||||
serializer.DataField(ref _airBlocked, "airBlocked", true);
|
serializer.DataField(ref _airBlocked, "airBlocked", true);
|
||||||
serializer.DataField(ref _fixVacuum, "fixVacuum", true);
|
serializer.DataField(ref _fixVacuum, "fixVacuum", true);
|
||||||
|
serializer.DataField(ref _airBlockedDirection, "airBlockedDirection", (int)AtmosDirection.All, WithFormat.Flags<AtmosDirectionFlags>());
|
||||||
|
serializer.DataField(ref _rotateAirBlocked, "rotateAirBlocked", true);
|
||||||
|
serializer.DataField(ref _fixAirBlockedDirectionInitialize, "fixAirBlockedDirectionInitialize", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
// Using the SnapGrid is critical for the performance of the room builder, and thus if
|
_atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||||
// it is absent the component will not be airtight. A warning is much easier to track
|
|
||||||
// down than the object magically not being airtight, so log one if the SnapGrid component
|
// Using the SnapGrid is critical for performance, and thus if it is absent the component
|
||||||
// is missing.
|
// will not be airtight. A warning is much easier to track down than the object magically
|
||||||
|
// not being airtight, so log one if the SnapGrid component is missing.
|
||||||
if (!Owner.EnsureComponent(out SnapGridComponent _))
|
if (!Owner.EnsureComponent(out SnapGridComponent _))
|
||||||
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition.ToString()} didn't have a {nameof(SnapGridComponent)}");
|
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition.ToString()} didn't have a {nameof(SnapGridComponent)}");
|
||||||
|
|
||||||
|
Owner.EntityManager.EventBus.SubscribeEvent<RotateEvent>(EventSource.Local, this, RotateEvent);
|
||||||
|
|
||||||
|
if(_fixAirBlockedDirectionInitialize)
|
||||||
|
RotateEvent(new RotateEvent(Owner, Angle.South, Owner.Transform.LocalRotation));
|
||||||
|
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RotateEvent(RotateEvent ev)
|
||||||
|
{
|
||||||
|
if (!_rotateAirBlocked || ev.Sender != Owner || ev.NewRotation == ev.OldRotation || AirBlockedDirection == AtmosDirection.Invalid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var diff = ev.NewRotation - ev.OldRotation;
|
||||||
|
|
||||||
|
var newAirBlockedDirs = AtmosDirection.Invalid;
|
||||||
|
|
||||||
|
// TODO ATMOS MULTIZ When we make multiZ atmos, special case this.
|
||||||
|
for (int i = 0; i < Atmospherics.Directions; i++)
|
||||||
|
{
|
||||||
|
var direction = (AtmosDirection) (1 << i);
|
||||||
|
if (!AirBlockedDirection.HasFlag(direction)) continue;
|
||||||
|
var angle = direction.ToAngle();
|
||||||
|
angle += diff;
|
||||||
|
newAirBlockedDirs |= angle.ToAtmosDirectionCardinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
AirBlockedDirection = newAirBlockedDirs;
|
||||||
|
}
|
||||||
|
|
||||||
public void MapInit()
|
public void MapInit()
|
||||||
{
|
{
|
||||||
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
|
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
|
||||||
@@ -89,13 +140,10 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
snapGrid.OnPositionChanged -= OnTransformMove;
|
snapGrid.OnPositionChanged -= OnTransformMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fixVacuum)
|
UpdatePosition(_lastPosition.Item1, _lastPosition.Item2);
|
||||||
{
|
|
||||||
var mapIndices = Owner.Transform.Coordinates.ToMapIndices(_entityManager, _mapManager);
|
|
||||||
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?.FixVacuum(mapIndices);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdatePosition();
|
if (_fixVacuum)
|
||||||
|
_atmosphereSystem.GetGridAtmosphere(_lastPosition.Item1)?.FixVacuum(_lastPosition.Item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTransformMove()
|
private void OnTransformMove()
|
||||||
@@ -111,13 +159,18 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
|
|
||||||
private void UpdatePosition()
|
private void UpdatePosition()
|
||||||
{
|
{
|
||||||
var mapIndices = Owner.Transform.Coordinates.ToMapIndices(_entityManager, _mapManager);
|
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
|
||||||
UpdatePosition(Owner.Transform.GridID, mapIndices);
|
UpdatePosition(Owner.Transform.GridID, snapGrid.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePosition(GridId gridId, MapIndices pos)
|
private void UpdatePosition(GridId gridId, MapIndices pos)
|
||||||
{
|
{
|
||||||
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(gridId)?.Invalidate(pos);
|
var gridAtmos = _atmosphereSystem.GetGridAtmosphere(gridId);
|
||||||
|
|
||||||
|
if (gridAtmos == null) return;
|
||||||
|
|
||||||
|
gridAtmos.UpdateAdjacentBits(pos);
|
||||||
|
gridAtmos.Invalidate(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
105
Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Atmos;
|
||||||
|
using Content.Server.GameObjects.Components.Doors;
|
||||||
|
using Content.Server.GameObjects.Components.Interactable;
|
||||||
|
using Content.Server.Interfaces;
|
||||||
|
using Content.Shared.GameObjects.Components.Doors;
|
||||||
|
using Content.Shared.GameObjects.Components.Interactable;
|
||||||
|
using Content.Shared.Interfaces;
|
||||||
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Components;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Atmos
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class FirelockComponent : ServerDoorComponent, IInteractUsing, ICollideBehavior
|
||||||
|
{
|
||||||
|
public override string Name => "Firelock";
|
||||||
|
|
||||||
|
protected override TimeSpan CloseTimeOne => TimeSpan.FromSeconds(0.1f);
|
||||||
|
protected override TimeSpan CloseTimeTwo => TimeSpan.FromSeconds(0.6f);
|
||||||
|
protected override TimeSpan OpenTimeOne => TimeSpan.FromSeconds(0.1f);
|
||||||
|
protected override TimeSpan OpenTimeTwo => TimeSpan.FromSeconds(0.6f);
|
||||||
|
|
||||||
|
public void CollideWith(IEntity collidedWith)
|
||||||
|
{
|
||||||
|
// We do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Startup()
|
||||||
|
{
|
||||||
|
base.Startup();
|
||||||
|
|
||||||
|
if (Owner.TryGetComponent(out AirtightComponent airtightComponent))
|
||||||
|
{
|
||||||
|
airtightComponent.AirBlocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Owner.TryGetComponent(out ICollidableComponent collidableComponent))
|
||||||
|
{
|
||||||
|
collidableComponent.Hard = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Safety = 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<AirtightComponent>().AirBlocked = true;
|
||||||
|
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanOpen()
|
||||||
|
{
|
||||||
|
return !IsHoldingFire() && !IsHoldingPressure() && base.CanOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanClose(IEntity user) => true;
|
||||||
|
public override bool CanOpen(IEntity user) => CanOpen();
|
||||||
|
|
||||||
|
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
if (!eventArgs.Using.TryGetComponent<ToolComponent>(out var tool))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tool.HasQuality(ToolQuality.Prying))
|
||||||
|
{
|
||||||
|
var holdingPressure = IsHoldingPressure();
|
||||||
|
var holdingFire = IsHoldingFire();
|
||||||
|
|
||||||
|
if (State == DoorState.Closed)
|
||||||
|
{
|
||||||
|
if(holdingPressure)
|
||||||
|
Owner.PopupMessage(eventArgs.User, "A gush of air blows in your face... Maybe you should reconsider.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await tool.UseTool(eventArgs.User, Owner, holdingPressure || holdingFire ? 1.5f : 0.25f, ToolQuality.Prying)) return false;
|
||||||
|
|
||||||
|
if (State == DoorState.Closed)
|
||||||
|
Open();
|
||||||
|
else if (State == DoorState.Open)
|
||||||
|
Close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,14 @@ using Content.Server.GameObjects.Components.Atmos.Piping;
|
|||||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
|
using Robust.Server.GameObjects.EntitySystems.TileLookup;
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Components.Map;
|
using Robust.Shared.GameObjects.Components.Map;
|
||||||
using Robust.Shared.GameObjects.Components.Transform;
|
using Robust.Shared.GameObjects.Components.Transform;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -32,6 +35,8 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
[Robust.Shared.IoC.Dependency] private ITileDefinitionManager _tileDefinitionManager = default!;
|
[Robust.Shared.IoC.Dependency] private ITileDefinitionManager _tileDefinitionManager = default!;
|
||||||
[Robust.Shared.IoC.Dependency] private IServerEntityManager _serverEntityManager = default!;
|
[Robust.Shared.IoC.Dependency] private IServerEntityManager _serverEntityManager = default!;
|
||||||
|
|
||||||
|
public GridTileLookupSystem GridTileLookupSystem { get; private set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check current execution time every n instances processed.
|
/// Check current execution time every n instances processed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -52,6 +57,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
private bool _paused = false;
|
private bool _paused = false;
|
||||||
private float _timer = 0f;
|
private float _timer = 0f;
|
||||||
private Stopwatch _stopwatch = new Stopwatch();
|
private Stopwatch _stopwatch = new Stopwatch();
|
||||||
|
private GridId _gridId;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public int UpdateCounter { get; private set; } = 0;
|
public int UpdateCounter { get; private set; } = 0;
|
||||||
@@ -155,23 +161,25 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual void PryTile(MapIndices indices)
|
public virtual void PryTile(MapIndices indices)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGridComponent)) return;
|
|
||||||
if (IsSpace(indices) || IsAirBlocked(indices)) return;
|
if (IsSpace(indices) || IsAirBlocked(indices)) return;
|
||||||
|
|
||||||
var mapGrid = mapGridComponent.Grid;
|
indices.PryTile(_gridId, _mapManager, _tileDefinitionManager, _serverEntityManager);
|
||||||
indices.PryTile(mapGrid.Index, _mapManager, _tileDefinitionManager, _serverEntityManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
RepopulateTiles();
|
RepopulateTiles();
|
||||||
|
|
||||||
|
GridTileLookupSystem = EntitySystem.Get<GridTileLookupSystem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnAdd()
|
public override void OnAdd()
|
||||||
{
|
{
|
||||||
base.OnAdd();
|
base.OnAdd();
|
||||||
RepopulateTiles();
|
|
||||||
|
if (Owner.TryGetComponent(out IMapGridComponent? mapGrid))
|
||||||
|
_gridId = mapGrid.GridIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void RepopulateTiles()
|
public virtual void RepopulateTiles()
|
||||||
@@ -182,6 +190,8 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
{
|
{
|
||||||
if(!Tiles.ContainsKey(tile.GridIndices))
|
if(!Tiles.ContainsKey(tile.GridIndices))
|
||||||
Tiles.Add(tile.GridIndices, new TileAtmosphere(this, tile.GridIndex, tile.GridIndices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}));
|
Tiles.Add(tile.GridIndices, new TileAtmosphere(this, tile.GridIndex, tile.GridIndices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}));
|
||||||
|
|
||||||
|
Invalidate(tile.GridIndices);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (_, tile) in Tiles.ToArray())
|
foreach (var (_, tile) in Tiles.ToArray())
|
||||||
@@ -199,16 +209,13 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
|
|
||||||
protected virtual void Revalidate()
|
protected virtual void Revalidate()
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
|
|
||||||
|
|
||||||
foreach (var indices in _invalidatedCoords.ToArray())
|
foreach (var indices in _invalidatedCoords.ToArray())
|
||||||
{
|
{
|
||||||
var tile = GetTile(indices);
|
var tile = GetTile(indices);
|
||||||
AddActiveTile(tile);
|
|
||||||
|
|
||||||
if (tile == null)
|
if (tile == null)
|
||||||
{
|
{
|
||||||
tile = new TileAtmosphere(this, mapGrid.Grid.Index, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C});
|
tile = new TileAtmosphere(this, _gridId, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C});
|
||||||
Tiles[indices] = tile;
|
Tiles[indices] = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,19 +231,19 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var obs = GetObstructingComponent(indices);
|
if (tile.Air == null && NeedsVacuumFixing(indices))
|
||||||
|
|
||||||
if (obs != null)
|
|
||||||
{
|
|
||||||
if (tile.Air == null && obs.FixVacuum)
|
|
||||||
{
|
{
|
||||||
FixVacuum(tile.GridIndices);
|
FixVacuum(tile.GridIndices);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tile.Air ??= new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
|
tile.Air ??= new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddActiveTile(tile);
|
||||||
|
tile.BlockedAirflow = GetBlockedDirections(indices);
|
||||||
|
|
||||||
|
// TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity
|
||||||
|
tile.ThermalConductivity = tile.Tile?.Tile.GetContentTileDefinition().ThermalConductivity ?? 0.5f;
|
||||||
tile.UpdateAdjacent();
|
tile.UpdateAdjacent();
|
||||||
tile.UpdateVisuals();
|
tile.UpdateVisuals();
|
||||||
|
|
||||||
@@ -246,19 +253,23 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
var otherIndices = indices.Offset(direction.ToDirection());
|
var otherIndices = indices.Offset(direction.ToDirection());
|
||||||
var otherTile = GetTile(otherIndices);
|
var otherTile = GetTile(otherIndices);
|
||||||
AddActiveTile(otherTile);
|
AddActiveTile(otherTile);
|
||||||
otherTile?.UpdateAdjacent(direction.GetOpposite());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_invalidatedCoords.Clear();
|
_invalidatedCoords.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void UpdateAdjacentBits(MapIndices indices)
|
||||||
|
{
|
||||||
|
GetTile(indices)?.UpdateAdjacent();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual void FixVacuum(MapIndices indices)
|
public virtual void FixVacuum(MapIndices indices)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
|
|
||||||
var tile = GetTile(indices);
|
var tile = GetTile(indices);
|
||||||
if (tile?.GridIndex != mapGrid.Grid.Index) return;
|
if (tile?.GridIndex != _gridId) return;
|
||||||
var adjacent = GetAdjacentTiles(indices);
|
var adjacent = GetAdjacentTiles(indices);
|
||||||
tile.Air = new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
|
tile.Air = new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
|
||||||
Tiles[indices] = tile;
|
Tiles[indices] = tile;
|
||||||
@@ -277,8 +288,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public virtual void AddActiveTile(TileAtmosphere? tile)
|
public virtual void AddActiveTile(TileAtmosphere? tile)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
|
if (tile?.GridIndex != _gridId) return;
|
||||||
if (tile?.GridIndex != mapGrid.Grid.Index) return;
|
|
||||||
tile.Excited = true;
|
tile.Excited = true;
|
||||||
_activeTiles.Add(tile);
|
_activeTiles.Add(tile);
|
||||||
}
|
}
|
||||||
@@ -297,8 +307,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public virtual void AddHotspotTile(TileAtmosphere? tile)
|
public virtual void AddHotspotTile(TileAtmosphere? tile)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
|
if (tile?.GridIndex != _gridId || tile?.Air == null) return;
|
||||||
if (tile?.GridIndex != mapGrid.Grid.Index || tile?.Air == null) return;
|
|
||||||
_hotspotTiles.Add(tile);
|
_hotspotTiles.Add(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,8 +321,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
|
|
||||||
public virtual void AddSuperconductivityTile(TileAtmosphere? tile)
|
public virtual void AddSuperconductivityTile(TileAtmosphere? tile)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
|
if (tile?.GridIndex != _gridId) return;
|
||||||
if (tile?.GridIndex != mapGrid.Grid.Index) return;
|
|
||||||
_superconductivityTiles.Add(tile);
|
_superconductivityTiles.Add(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,8 +335,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public virtual void AddHighPressureDelta(TileAtmosphere? tile)
|
public virtual void AddHighPressureDelta(TileAtmosphere? tile)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
|
if (tile?.GridIndex != _gridId) return;
|
||||||
if (tile?.GridIndex != mapGrid.Grid.Index) return;
|
|
||||||
_highPressureDelta.Add(tile);
|
_highPressureDelta.Add(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,24 +389,30 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TileAtmosphere? GetTile(MapIndices indices, bool createSpace = true)
|
public TileAtmosphere? GetTile(MapIndices indices, bool createSpace = true)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return null;
|
|
||||||
|
|
||||||
if (Tiles.TryGetValue(indices, out var tile)) return tile;
|
if (Tiles.TryGetValue(indices, out var tile)) return tile;
|
||||||
|
|
||||||
// We don't have that tile!
|
// We don't have that tile!
|
||||||
if (IsSpace(indices) && createSpace)
|
if (IsSpace(indices) && createSpace)
|
||||||
{
|
{
|
||||||
return new TileAtmosphere(this, mapGrid.Grid.Index, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.TCMB}, true);
|
return new TileAtmosphere(this, _gridId, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.TCMB}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsAirBlocked(MapIndices indices)
|
public bool IsAirBlocked(MapIndices indices, AtmosDirection direction = AtmosDirection.All)
|
||||||
{
|
{
|
||||||
var ac = GetObstructingComponent(indices);
|
foreach (var obstructingComponent in GetObstructingComponents(indices))
|
||||||
return ac != null && ac.AirBlocked;
|
{
|
||||||
|
if (!obstructingComponent.AirBlocked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (obstructingComponent.AirBlockedDirection.HasFlag(direction))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -763,17 +776,43 @@ namespace Content.Server.GameObjects.Components.Atmos
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AirtightComponent? GetObstructingComponent(MapIndices indices)
|
private IEnumerable<AirtightComponent> GetObstructingComponents(MapIndices indices)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return default;
|
var gridLookup = EntitySystem.Get<GridTileLookupSystem>();
|
||||||
|
|
||||||
foreach (var v in mapGrid.Grid.GetSnapGridCell(indices, SnapGridOffset.Center))
|
var list = new List<AirtightComponent>();
|
||||||
|
|
||||||
|
foreach (var v in gridLookup.GetEntitiesIntersecting(_gridId, indices))
|
||||||
{
|
{
|
||||||
if (v.Owner.TryGetComponent<AirtightComponent>(out var ac))
|
if (v.TryGetComponent<AirtightComponent>(out var ac))
|
||||||
return ac;
|
list.Add(ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool NeedsVacuumFixing(MapIndices indices)
|
||||||
|
{
|
||||||
|
var value = false;
|
||||||
|
|
||||||
|
foreach (var airtightComponent in GetObstructingComponents(indices))
|
||||||
|
{
|
||||||
|
value |= airtightComponent.FixVacuum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AtmosDirection GetBlockedDirections(MapIndices indices)
|
||||||
|
{
|
||||||
|
var value = AtmosDirection.Invalid;
|
||||||
|
|
||||||
|
foreach (var airtightComponent in GetObstructingComponents(indices))
|
||||||
|
{
|
||||||
|
value |= airtightComponent.AirBlockedDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Content.Server.Atmos;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.GameObjects.Components.Access;
|
using Content.Server.GameObjects.Components.Access;
|
||||||
using Content.Server.GameObjects.Components.Atmos;
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
@@ -54,11 +55,11 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
|
|
||||||
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
private static readonly TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.3f);
|
protected virtual TimeSpan CloseTimeOne => TimeSpan.FromSeconds(0.3f);
|
||||||
private static readonly TimeSpan CloseTimeTwo = TimeSpan.FromSeconds(0.9f);
|
protected virtual TimeSpan CloseTimeTwo => TimeSpan.FromSeconds(0.9f);
|
||||||
private static readonly TimeSpan OpenTimeOne = TimeSpan.FromSeconds(0.3f);
|
protected virtual TimeSpan OpenTimeOne => TimeSpan.FromSeconds(0.3f);
|
||||||
private static readonly TimeSpan OpenTimeTwo = TimeSpan.FromSeconds(0.9f);
|
protected virtual TimeSpan OpenTimeTwo => TimeSpan.FromSeconds(0.9f);
|
||||||
private static readonly TimeSpan DenyTime = TimeSpan.FromSeconds(0.45f);
|
protected virtual TimeSpan DenyTime => TimeSpan.FromSeconds(0.45f);
|
||||||
|
|
||||||
private const int DoorCrushDamage = 15;
|
private const int DoorCrushDamage = 15;
|
||||||
private const float DoorStunTime = 5f;
|
private const float DoorStunTime = 5f;
|
||||||
@@ -67,6 +68,8 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] private bool _occludes;
|
[ViewVariables(VVAccess.ReadWrite)] private bool _occludes;
|
||||||
|
|
||||||
|
public bool Occludes => _occludes;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool IsWeldedShut
|
public bool IsWeldedShut
|
||||||
{
|
{
|
||||||
@@ -86,12 +89,16 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
|
|
||||||
private bool _canWeldShut = true;
|
private bool _canWeldShut = true;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
private bool _canCrush = true;
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
{
|
{
|
||||||
base.ExposeData(serializer);
|
base.ExposeData(serializer);
|
||||||
|
|
||||||
serializer.DataField(ref _occludes, "occludes", true);
|
serializer.DataField(ref _occludes, "occludes", true);
|
||||||
serializer.DataField(ref _isWeldedShut, "welded", false);
|
serializer.DataField(ref _isWeldedShut, "welded", false);
|
||||||
|
serializer.DataField(ref _canCrush, "canCrush", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnRemove()
|
public override void OnRemove()
|
||||||
@@ -146,7 +153,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAppearance(DoorVisualState state)
|
protected void SetAppearance(DoorVisualState state)
|
||||||
{
|
{
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||||
{
|
{
|
||||||
@@ -159,7 +166,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
return !_isWeldedShut;
|
return !_isWeldedShut;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanOpen(IEntity user)
|
public virtual bool CanOpen(IEntity user)
|
||||||
{
|
{
|
||||||
if (!CanOpen()) return false;
|
if (!CanOpen()) return false;
|
||||||
|
|
||||||
@@ -253,7 +260,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanClose(IEntity user)
|
public virtual bool CanClose(IEntity user)
|
||||||
{
|
{
|
||||||
if (!CanClose()) return false;
|
if (!CanClose()) return false;
|
||||||
if (!Owner.TryGetComponent(out AccessReader? accessReader))
|
if (!Owner.TryGetComponent(out AccessReader? accessReader))
|
||||||
@@ -313,11 +320,62 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsHoldingPressure(float threshold = 20)
|
||||||
|
{
|
||||||
|
var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||||
|
|
||||||
|
if (!Owner.Transform.Coordinates.TryGetTileAtmosphere(out var tileAtmos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var gridAtmosphere = atmosphereSystem.GetGridAtmosphere(Owner.Transform.GridID);
|
||||||
|
|
||||||
|
if (gridAtmosphere == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var minMoles = float.MaxValue;
|
||||||
|
var maxMoles = 0f;
|
||||||
|
|
||||||
|
foreach (var (direction, adjacent) in gridAtmosphere.GetAdjacentTiles(tileAtmos.GridIndices))
|
||||||
|
{
|
||||||
|
var moles = adjacent.Air.TotalMoles;
|
||||||
|
if (moles < minMoles)
|
||||||
|
minMoles = moles;
|
||||||
|
if (moles > maxMoles)
|
||||||
|
maxMoles = moles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (maxMoles - minMoles) > threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHoldingFire()
|
||||||
|
{
|
||||||
|
var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||||
|
|
||||||
|
if (!Owner.Transform.Coordinates.TryGetTileAtmosphere(out var tileAtmos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tileAtmos.Hotspot.Valid)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var gridAtmosphere = atmosphereSystem.GetGridAtmosphere(Owner.Transform.GridID);
|
||||||
|
|
||||||
|
if (gridAtmosphere == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var (direction, adjacent) in gridAtmosphere.GetAdjacentTiles(tileAtmos.GridIndices))
|
||||||
|
{
|
||||||
|
if (adjacent.Hotspot.Valid)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Close()
|
public bool Close()
|
||||||
{
|
{
|
||||||
bool shouldCheckCrush = false;
|
bool shouldCheckCrush = false;
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out ICollidableComponent? collidable) && collidable.IsColliding(Vector2.Zero, false))
|
if (_canCrush && Owner.TryGetComponent(out ICollidableComponent? collidable) && collidable.IsColliding(Vector2.Zero, false))
|
||||||
{
|
{
|
||||||
if (Safety)
|
if (Safety)
|
||||||
return false;
|
return false;
|
||||||
@@ -336,7 +394,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
|
|
||||||
Timer.Spawn(CloseTimeOne, async () =>
|
Timer.Spawn(CloseTimeOne, async () =>
|
||||||
{
|
{
|
||||||
if (shouldCheckCrush)
|
if (shouldCheckCrush && _canCrush)
|
||||||
{
|
{
|
||||||
CheckCrush();
|
CheckCrush();
|
||||||
}
|
}
|
||||||
|
|||||||
40
Content.Server/Utility/GridTileLookupHelpers.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Robust.Server.GameObjects.EntitySystems.TileLookup;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Server.Utility
|
||||||
|
{
|
||||||
|
public static class GridTileLookupHelpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper that returns all entities in a turf very fast.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IEnumerable<IEntity> GetEntitiesInTileFast(this TileRef turf, GridTileLookupSystem? gridTileLookup = null)
|
||||||
|
{
|
||||||
|
gridTileLookup ??= EntitySystem.Get<GridTileLookupSystem>();
|
||||||
|
|
||||||
|
return gridTileLookup.GetEntitiesIntersecting(turf.GridIndex, turf.GridIndices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper that returns all entities in a turf.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IEnumerable<IEntity> GetEntitiesInTileFast(this MapIndices indices, GridId gridId, GridTileLookupSystem? gridTileLookup = null)
|
||||||
|
{
|
||||||
|
var turf = indices.GetTileRef(gridId);
|
||||||
|
|
||||||
|
if (turf == null)
|
||||||
|
return Enumerable.Empty<IEntity>();
|
||||||
|
|
||||||
|
return GetEntitiesInTileFast(turf.Value, gridTileLookup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Atmos
|
namespace Content.Shared.Atmos
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The reason we use this over <see cref="Direction"/> is that we are going to do some heavy bitflag usage.
|
/// The reason we use this over <see cref="Direction"/> is that we are going to do some heavy bitflag usage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
[Flags, Serializable]
|
||||||
public enum AtmosDirection : byte
|
[FlagsFor(typeof(AtmosDirectionFlags))]
|
||||||
|
public enum AtmosDirection
|
||||||
{
|
{
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
North = 1 << 0,
|
North = 1 << 0,
|
||||||
@@ -75,6 +77,49 @@ namespace Content.Shared.Atmos
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a direction to an angle, where angle is -PI to +PI.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="direction"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Angle ToAngle(this AtmosDirection direction)
|
||||||
|
{
|
||||||
|
return direction switch
|
||||||
|
{
|
||||||
|
AtmosDirection.East => Angle.FromDegrees(0),
|
||||||
|
AtmosDirection.North => Angle.FromDegrees(90),
|
||||||
|
AtmosDirection.West => Angle.FromDegrees(180),
|
||||||
|
AtmosDirection.South => Angle.FromDegrees(270),
|
||||||
|
|
||||||
|
AtmosDirection.NorthEast => Angle.FromDegrees(45),
|
||||||
|
AtmosDirection.NorthWest => Angle.FromDegrees(135),
|
||||||
|
AtmosDirection.SouthWest => Angle.FromDegrees(225),
|
||||||
|
AtmosDirection.SouthEast => Angle.FromDegrees(315),
|
||||||
|
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(direction), $"It was {direction}."),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an angle to a cardinal AtmosDirection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static AtmosDirection ToAtmosDirectionCardinal(this Angle angle)
|
||||||
|
{
|
||||||
|
return angle.GetCardinalDir().ToAtmosDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an angle to an AtmosDirection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static AtmosDirection ToAtmosDirection(this Angle angle)
|
||||||
|
{
|
||||||
|
return angle.GetDir().ToAtmosDirection();
|
||||||
|
}
|
||||||
|
|
||||||
public static int ToIndex(this AtmosDirection direction)
|
public static int ToIndex(this AtmosDirection direction)
|
||||||
{
|
{
|
||||||
// This will throw if you pass an invalid direction. Not this method's fault, but yours!
|
// This will throw if you pass an invalid direction. Not this method's fault, but yours!
|
||||||
@@ -85,5 +130,12 @@ namespace Content.Shared.Atmos
|
|||||||
{
|
{
|
||||||
return direction | other;
|
return direction | other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AtmosDirection WithoutFlag(this AtmosDirection direction, AtmosDirection other)
|
||||||
|
{
|
||||||
|
return direction & ~other;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class AtmosDirectionFlags { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Utility;
|
using Content.Shared.Utility;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
using Robust.Shared.Interfaces.Physics;
|
using Robust.Shared.Interfaces.Physics;
|
||||||
@@ -57,7 +60,7 @@ namespace Content.Shared.Maps
|
|||||||
if (!mapManager.TryGetGrid(coordinates.GetGridId(entityManager), out var grid))
|
if (!mapManager.TryGetGrid(coordinates.GetGridId(entityManager), out var grid))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!grid.TryGetTileRef(coordinates.ToMapIndices(entityManager, mapManager), out var tile))
|
if (!grid.TryGetTileRef(coordinates, out var tile))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return tile;
|
return tile;
|
||||||
@@ -120,13 +123,40 @@ namespace Content.Shared.Maps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper that returns all entities in a turf.
|
/// Helper that returns all entities in a turf.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<IEntity> GetEntitiesInTile(this TileRef turf, bool approximate = false)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IEnumerable<IEntity> GetEntitiesInTile(this TileRef turf, bool approximate = false, IEntityManager? entityManager = null)
|
||||||
{
|
{
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
entityManager ??= IoCManager.Resolve<IEntityManager>();
|
||||||
|
|
||||||
return entityManager.GetEntitiesIntersecting(turf.MapIndex, GetWorldTileBox(turf), approximate);
|
return entityManager.GetEntitiesIntersecting(turf.MapIndex, GetWorldTileBox(turf), approximate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper that returns all entities in a turf.
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<IEntity> GetEntitiesInTile(this EntityCoordinates coordinates, bool approximate = false, IEntityManager? entityManager = null)
|
||||||
|
{
|
||||||
|
var turf = coordinates.GetTileRef();
|
||||||
|
|
||||||
|
if (turf == null)
|
||||||
|
return Enumerable.Empty<IEntity>();
|
||||||
|
|
||||||
|
return GetEntitiesInTile(turf.Value, approximate, entityManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper that returns all entities in a turf.
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<IEntity> GetEntitiesInTile(this MapIndices indices, GridId gridId, bool approximate = false, IEntityManager? entityManager = null)
|
||||||
|
{
|
||||||
|
var turf = indices.GetTileRef(gridId);
|
||||||
|
|
||||||
|
if (turf == null)
|
||||||
|
return Enumerable.Empty<IEntity>();
|
||||||
|
|
||||||
|
return GetEntitiesInTile(turf.Value, approximate, entityManager);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a turf has something dense on it.
|
/// Checks if a turf has something dense on it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -56,7 +56,6 @@
|
|||||||
type: WiresBoundUserInterface
|
type: WiresBoundUserInterface
|
||||||
- type: Airtight
|
- type: Airtight
|
||||||
fixVacuum: true
|
fixVacuum: true
|
||||||
adjacentAtmosphere: true
|
|
||||||
- type: Occluder
|
- type: Occluder
|
||||||
- type: SnapGrid
|
- type: SnapGrid
|
||||||
offset: Center
|
offset: Center
|
||||||
|
|||||||
108
Resources/Prototypes/Entities/Constructible/Doors/firelock.yml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
- 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: welded
|
||||||
|
map: ["enum.DoorVisualLayers.BaseWelded"]
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: FirelockEdge
|
||||||
|
parent: Firelock
|
||||||
|
name: firelock
|
||||||
|
prefix: south
|
||||||
|
components:
|
||||||
|
- type: Firelock
|
||||||
|
occludes: false
|
||||||
|
canCrush: false
|
||||||
|
- type: Occluder
|
||||||
|
enabled: false
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Constructible/Structures/Doors/edge_door_hazard.rsi
|
||||||
|
- type: Icon
|
||||||
|
sprite: Constructible/Structures/Doors/edge_door_hazard.rsi
|
||||||
|
- type: Airtight
|
||||||
|
fixVacuum: true
|
||||||
|
airBlockedDirection:
|
||||||
|
- South
|
||||||
|
- type: Collidable
|
||||||
|
shapes:
|
||||||
|
- !type:PhysShapeAabb
|
||||||
|
bounds: "-0.49,-0.49,-0.2,0.49" # don't want this colliding with walls or they won't close
|
||||||
|
mask:
|
||||||
|
- MobImpassable
|
||||||
|
layer:
|
||||||
|
- Opaque
|
||||||
|
- Impassable
|
||||||
|
- MobImpassable
|
||||||
|
- VaultImpassable
|
||||||
|
- SmallImpassable
|
||||||
|
After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,430 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"license": "CC-BY-SA 3.0",
|
||||||
|
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13/ at 38b65a605df7ae2907d6bf0d4aebc5faa1bbc561",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "alert_cold",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alert_hot",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bolted",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closed",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closed_unlit",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closing",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closing_unlit",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "deny",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "deny_unlit",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "locked",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "open",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "opening",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "opening_unlit",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "palert",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "welded_open",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 805 B |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 468 B |
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 193 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 359 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,227 @@
|
|||||||
|
{
|
||||||
|
"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": "bolted",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closed",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closed_unlit",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closing",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closing_unlit",
|
||||||
|
"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": "deny_unlit",
|
||||||
|
"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": "opening_unlit",
|
||||||
|
"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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 639 B |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 193 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,191 @@
|
|||||||
|
{
|
||||||
|
"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": "bolted",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closed",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closed_unlit",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closing",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "closing_unlit",
|
||||||
|
"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": "deny_unlit",
|
||||||
|
"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": "opening_unlit",
|
||||||
|
"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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 563 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 193 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 321 B |
@@ -66,6 +66,7 @@
|
|||||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data></s:String>
|
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data></s:String>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Collidable/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Collidable/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cooldowns/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cooldowns/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Firelock/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=cvar/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=cvar/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=cvars/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=cvars/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Discharger/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Discharger/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||