using System.Threading.Tasks; using Content.Shared.Maps; using Content.Shared.Procedural; using Content.Shared.Procedural.PostGeneration; using Content.Shared.Storage; using Robust.Shared.Random; namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { /// /// /// private async Task PostGen(DungeonEntranceDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) { if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entrance)) { LogDataError(typeof(DungeonEntranceDunGen)); return; } var rooms = new List(dungeon.Rooms); var roomTiles = new List(); var tileDef = (ContentTileDefinition) _tileDefManager[tileProto]; for (var i = 0; i < gen.Count; i++) { var roomIndex = random.Next(rooms.Count); var room = rooms[roomIndex]; // Move out 3 tiles in a direction away from center of the room // If none of those intersect another tile it's probably external // TODO: Maybe need to take top half of furthest rooms in case there's interior exits? roomTiles.AddRange(room.Exterior); random.Shuffle(roomTiles); foreach (var tile in roomTiles) { var isValid = false; // Check if one side is dungeon and the other side is nothing. for (var j = 0; j < 4; j++) { var dir = (Direction) (j * 2); var oppositeDir = dir.GetOpposite(); var dirVec = tile + dir.ToIntVec(); var oppositeDirVec = tile + oppositeDir.ToIntVec(); if (!dungeon.RoomTiles.Contains(dirVec)) { continue; } if (dungeon.RoomTiles.Contains(oppositeDirVec) || dungeon.RoomExteriorTiles.Contains(oppositeDirVec) || dungeon.CorridorExteriorTiles.Contains(oppositeDirVec) || dungeon.CorridorTiles.Contains(oppositeDirVec)) { continue; } // Check if exterior spot free. if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) { continue; } // Check if interior spot free (no guarantees on exterior but ClearDoor should handle it) if (!_anchorable.TileFree(_grid, dirVec, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) { continue; } // Valid pick! isValid = true; // Entrance wew _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile(tileDef, random)); ClearDoor(dungeon, _grid, tile); var gridCoords = _maps.GridTileToLocal(_gridUid, _grid, tile); // Need to offset the spawn to avoid spawning in the room. foreach (var ent in EntitySpawnCollection.GetSpawns(_prototype.Index(entrance).Entries, random)) { _entManager.SpawnAtPosition(ent, gridCoords); } // Clear out any biome tiles nearby to avoid blocking it foreach (var nearTile in _maps.GetLocalTilesIntersecting(_gridUid, _grid, new Circle(gridCoords.Position, 1.5f), false)) { if (dungeon.RoomTiles.Contains(nearTile.GridIndices) || dungeon.RoomExteriorTiles.Contains(nearTile.GridIndices) || dungeon.CorridorTiles.Contains(nearTile.GridIndices) || dungeon.CorridorExteriorTiles.Contains(nearTile.GridIndices)) { continue; } _maps.SetTile(_gridUid, _grid, nearTile.GridIndices, _tile.GetVariantTile(tileDef, random)); } break; } if (isValid) break; } roomTiles.Clear(); } } }