diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs index c444afa834..902f2188e2 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs @@ -86,14 +86,6 @@ public sealed partial class PuddleSystem : SharedPuddleSystem return; } - var xform = Transform(uid); - - if (!TryComp(xform.GridUid, out var grid)) - { - RemCompDeferred(uid); - return; - } - var puddleQuery = GetEntityQuery(); // For overflows, we never go to a fully evaporative tile just to avoid continuously having to mop it. @@ -152,10 +144,10 @@ public sealed partial class PuddleSystem : SharedPuddleSystem spillCount = Math.Min(args.NeighborFreeTiles.Count, spillCount); var spillAmount = overflow.Volume / spillCount; - foreach (var tile in args.NeighborFreeTiles) + foreach (var neighbor in args.NeighborFreeTiles) { var split = overflow.SplitSolution(spillAmount); - TrySpillAt(grid.GridTileToLocal(tile), split, out _, false); + TrySpillAt(neighbor.Grid.GridTileToLocal(neighbor.Tile), split, out _, false); args.Updates--; if (args.Updates <= 0) diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index 2a6aa936b9..b489cbc2a4 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -73,7 +73,6 @@ public sealed class SmokeSystem : EntitySystem private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args) { if (component.SpreadAmount == 0 || - args.Grid == null || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) || args.NeighborFreeTiles.Count == 0) { @@ -94,9 +93,9 @@ public sealed class SmokeSystem : EntitySystem var smokePerSpread = component.SpreadAmount / args.NeighborFreeTiles.Count; component.SpreadAmount -= smokePerSpread; - foreach (var tile in args.NeighborFreeTiles) + foreach (var neighbor in args.NeighborFreeTiles) { - var coords = args.Grid.GridTileToLocal(tile); + var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile); var ent = Spawn(prototype.ID, coords.SnapToGrid()); var neighborSmoke = EnsureComp(ent); neighborSmoke.SpreadAmount = Math.Max(0, smokePerSpread - 1); diff --git a/Content.Server/Spreader/KudzuSystem.cs b/Content.Server/Spreader/KudzuSystem.cs index 49b1a84d56..407d99e478 100644 --- a/Content.Server/Spreader/KudzuSystem.cs +++ b/Content.Server/Spreader/KudzuSystem.cs @@ -28,7 +28,7 @@ public sealed class KudzuSystem : EntitySystem return; } - if (args.NeighborFreeTiles.Count == 0 || args.Grid == null) + if (args.NeighborFreeTiles.Count == 0) { RemCompDeferred(uid); return; @@ -47,7 +47,7 @@ public sealed class KudzuSystem : EntitySystem foreach (var neighbor in args.NeighborFreeTiles) { - var neighborUid = Spawn(prototype, args.Grid.GridTileToLocal(neighbor)); + var neighborUid = Spawn(prototype, neighbor.Grid.GridTileToLocal(neighbor.Tile)); EnsureComp(neighborUid); args.Updates--; diff --git a/Content.Server/Spreader/SpreadNeighborsEvent.cs b/Content.Server/Spreader/SpreadNeighborsEvent.cs index 723e510d60..0cee55b588 100644 --- a/Content.Server/Spreader/SpreadNeighborsEvent.cs +++ b/Content.Server/Spreader/SpreadNeighborsEvent.cs @@ -10,9 +10,7 @@ namespace Content.Server.Spreader; [ByRefEvent] public record struct SpreadNeighborsEvent { - public MapGridComponent? Grid; - public ValueList NeighborFreeTiles; - public ValueList NeighborOccupiedTiles; + public ValueList<(MapGridComponent Grid, Vector2i Tile)> NeighborFreeTiles; public ValueList Neighbors; /// @@ -20,4 +18,4 @@ public record struct SpreadNeighborsEvent /// Subscribers can handle as they wish. /// public int Updates; -} \ No newline at end of file +} diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index a9d4d49628..b39f83e4a2 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -2,8 +2,10 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.NodeContainer; using Content.Server.NodeContainer.NodeGroups; +using Content.Server.Shuttles.Components; using Content.Shared.Atmos; using Content.Shared.Spreader; +using Content.Shared.Tag; using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -27,6 +29,8 @@ public sealed class SpreaderSystem : EntitySystem private readonly List _spreaderGroups = new(); + private const string IgnoredTag = "SpreaderIgnore"; + /// public override void Initialize() { @@ -178,15 +182,11 @@ public sealed class SpreaderSystem : EntitySystem private void Spread(EntityUid uid, SpreaderNode node, INodeGroup group, ref int updates) { - GetNeighbors(uid, node.Name, out var freeTiles, out var occupiedTiles, out var neighbors); - - TryComp(Transform(uid).GridUid, out var grid); + GetNeighbors(uid, node.Name, out var freeTiles, out _, out var neighbors); var ev = new SpreadNeighborsEvent() { - Grid = grid, NeighborFreeTiles = freeTiles, - NeighborOccupiedTiles = occupiedTiles, Neighbors = neighbors, Updates = updates, }; @@ -198,9 +198,9 @@ public sealed class SpreaderSystem : EntitySystem /// /// Gets the neighboring node data for the specified entity and the specified node group. /// - public void GetNeighbors(EntityUid uid, string groupName, out ValueList freeTiles, out ValueList occupiedTiles, out ValueList neighbors) + public void GetNeighbors(EntityUid uid, string groupName, out ValueList<(MapGridComponent Grid, Vector2i Tile)> freeTiles, out ValueList occupiedTiles, out ValueList neighbors) { - freeTiles = new ValueList(); + freeTiles = new ValueList<(MapGridComponent Grid, Vector2i Tile)>(); occupiedTiles = new ValueList(); neighbors = new ValueList(); @@ -213,47 +213,82 @@ public sealed class SpreaderSystem : EntitySystem var tile = grid.TileIndicesFor(transform.Coordinates); var nodeQuery = GetEntityQuery(); var airtightQuery = GetEntityQuery(); + var dockQuery = GetEntityQuery(); + var xformQuery = GetEntityQuery(); + var tagQuery = GetEntityQuery(); + var blockedAtmosDirs = AtmosDirection.Invalid; + // Due to docking ports they may not necessarily be opposite directions. + var neighborTiles = new ValueList<(MapGridComponent grid, Vector2i Indices, AtmosDirection OtherDir, AtmosDirection OurDir)>(); + + // Check if anything on our own tile blocking that direction. + var ourEnts = grid.GetAnchoredEntitiesEnumerator(tile); + + while (ourEnts.MoveNext(out var ent)) + { + // Spread via docks in a special-case. + if (dockQuery.TryGetComponent(ent, out var dock) && + dock.Docked && + xformQuery.TryGetComponent(ent, out var xform) && + xformQuery.TryGetComponent(dock.DockedWith, out var dockedXform) && + TryComp(dockedXform.GridUid, out var dockedGrid)) + { + neighborTiles.Add((dockedGrid, dockedGrid.CoordinatesToTile(dockedXform.Coordinates), xform.LocalRotation.ToAtmosDirection(), dockedXform.LocalRotation.ToAtmosDirection())); + } + + // If we're on a blocked tile work out which directions we can go. + if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || + tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag)) + { + continue; + } + + foreach (var value in new[] { AtmosDirection.North, AtmosDirection.East, AtmosDirection.South, AtmosDirection.West}) + { + if ((value & airtight.AirBlockedDirection) == 0x0) + continue; + + blockedAtmosDirs |= value; + break; + } + break; + } + + // Add the normal neighbors. for (var i = 0; i < 4; i++) { var direction = (Direction) (i * 2); + var atmosDir = direction.ToAtmosDirection(); var neighborPos = SharedMapSystem.GetDirection(tile, direction); + neighborTiles.Add((grid, neighborPos, atmosDir, atmosDir.GetOpposite())); + } - if (!grid.TryGetTileRef(neighborPos, out var tileRef) || tileRef.Tile.IsEmpty) + foreach (var (neighborGrid, neighborPos, ourAtmosDir, otherAtmosDir) in neighborTiles) + { + // This tile is blocked to that direction. + if ((blockedAtmosDirs & ourAtmosDir) != 0x0) + continue; + + if (!neighborGrid.TryGetTileRef(neighborPos, out var tileRef) || tileRef.Tile.IsEmpty) continue; var directionEnumerator = - grid.GetAnchoredEntitiesEnumerator(neighborPos); + neighborGrid.GetAnchoredEntitiesEnumerator(neighborPos); var occupied = false; while (directionEnumerator.MoveNext(out var ent)) { - if (airtightQuery.TryGetComponent(ent, out var airtight) && airtight.AirBlocked) + if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || + tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag)) { - // Check if air direction matters. - var blocked = false; - - foreach (var value in new[] { AtmosDirection.North, AtmosDirection.East}) - { - if ((value & airtight.AirBlockedDirection) == 0x0) - continue; - - var airDirection = value.ToDirection(); - var oppositeDirection = value.ToDirection().GetOpposite(); - - if (direction != airDirection && direction != oppositeDirection) - continue; - - blocked = true; - break; - } - - if (!blocked) - continue; - - occupied = true; - break; + continue; } + + if ((airtight.AirBlockedDirection & otherAtmosDir) == 0x0) + continue; + + occupied = true; + break; } if (occupied) @@ -261,7 +296,7 @@ public sealed class SpreaderSystem : EntitySystem var oldCount = occupiedTiles.Count; directionEnumerator = - grid.GetAnchoredEntitiesEnumerator(neighborPos); + neighborGrid.GetAnchoredEntitiesEnumerator(neighborPos); while (directionEnumerator.MoveNext(out var ent)) { @@ -277,7 +312,7 @@ public sealed class SpreaderSystem : EntitySystem } if (oldCount == occupiedTiles.Count) - freeTiles.Add(neighborPos); + freeTiles.Add((neighborGrid, neighborPos)); } } diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml index 117329cdd9..a06578fc46 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml @@ -43,10 +43,7 @@ path: /Audio/Machines/airlock_deny.ogg - type: Airtight fixVacuum: true - airBlockedDirection: - - East - - West - - South + noAirWhenFullyAirBlocked: false - type: Tag tags: - ForceNoFixRotations diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml index c597788c6c..ceae3eed4b 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml @@ -22,3 +22,6 @@ - type: Airtight noAirWhenFullyAirBlocked: false - type: Clickable + - type: Tag + tags: + - SpreaderIgnore diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index ae37ea4f3f..d1d13271d8 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -607,6 +607,9 @@ - type: Tag id: SpeedLoaderRifle +- type: Tag + id: SpreaderIgnore + - type: Tag id: StringInstrument