DungeonJob.PostGenDungeonEntrance.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System.Threading.Tasks;
  2. using Content.Shared.Maps;
  3. using Content.Shared.Procedural;
  4. using Content.Shared.Procedural.PostGeneration;
  5. using Content.Shared.Storage;
  6. using Robust.Shared.Random;
  7. namespace Content.Server.Procedural.DungeonJob;
  8. public sealed partial class DungeonJob
  9. {
  10. /// <summary>
  11. /// <see cref="DungeonEntranceDunGen"/>
  12. /// </summary>
  13. private async Task PostGen(DungeonEntranceDunGen gen, DungeonData data, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
  14. {
  15. if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) ||
  16. !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entrance))
  17. {
  18. LogDataError(typeof(DungeonEntranceDunGen));
  19. return;
  20. }
  21. var rooms = new List<DungeonRoom>(dungeon.Rooms);
  22. var roomTiles = new List<Vector2i>();
  23. var tileDef = (ContentTileDefinition) _tileDefManager[tileProto];
  24. for (var i = 0; i < gen.Count; i++)
  25. {
  26. var roomIndex = random.Next(rooms.Count);
  27. var room = rooms[roomIndex];
  28. // Move out 3 tiles in a direction away from center of the room
  29. // If none of those intersect another tile it's probably external
  30. // TODO: Maybe need to take top half of furthest rooms in case there's interior exits?
  31. roomTiles.AddRange(room.Exterior);
  32. random.Shuffle(roomTiles);
  33. foreach (var tile in roomTiles)
  34. {
  35. var isValid = false;
  36. // Check if one side is dungeon and the other side is nothing.
  37. for (var j = 0; j < 4; j++)
  38. {
  39. var dir = (Direction) (j * 2);
  40. var oppositeDir = dir.GetOpposite();
  41. var dirVec = tile + dir.ToIntVec();
  42. var oppositeDirVec = tile + oppositeDir.ToIntVec();
  43. if (!dungeon.RoomTiles.Contains(dirVec))
  44. {
  45. continue;
  46. }
  47. if (dungeon.RoomTiles.Contains(oppositeDirVec) ||
  48. dungeon.RoomExteriorTiles.Contains(oppositeDirVec) ||
  49. dungeon.CorridorExteriorTiles.Contains(oppositeDirVec) ||
  50. dungeon.CorridorTiles.Contains(oppositeDirVec))
  51. {
  52. continue;
  53. }
  54. // Check if exterior spot free.
  55. if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
  56. {
  57. continue;
  58. }
  59. // Check if interior spot free (no guarantees on exterior but ClearDoor should handle it)
  60. if (!_anchorable.TileFree(_grid, dirVec, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
  61. {
  62. continue;
  63. }
  64. // Valid pick!
  65. isValid = true;
  66. // Entrance wew
  67. _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile(tileDef, random));
  68. ClearDoor(dungeon, _grid, tile);
  69. var gridCoords = _maps.GridTileToLocal(_gridUid, _grid, tile);
  70. // Need to offset the spawn to avoid spawning in the room.
  71. foreach (var ent in EntitySpawnCollection.GetSpawns(_prototype.Index(entrance).Entries, random))
  72. {
  73. _entManager.SpawnAtPosition(ent, gridCoords);
  74. }
  75. // Clear out any biome tiles nearby to avoid blocking it
  76. foreach (var nearTile in _maps.GetLocalTilesIntersecting(_gridUid, _grid, new Circle(gridCoords.Position, 1.5f), false))
  77. {
  78. if (dungeon.RoomTiles.Contains(nearTile.GridIndices) ||
  79. dungeon.RoomExteriorTiles.Contains(nearTile.GridIndices) ||
  80. dungeon.CorridorTiles.Contains(nearTile.GridIndices) ||
  81. dungeon.CorridorExteriorTiles.Contains(nearTile.GridIndices))
  82. {
  83. continue;
  84. }
  85. _maps.SetTile(_gridUid, _grid, nearTile.GridIndices, _tile.GetVariantTile(tileDef, random));
  86. }
  87. break;
  88. }
  89. if (isValid)
  90. break;
  91. }
  92. roomTiles.Clear();
  93. }
  94. }
  95. }