1
0

DungeonJob.PostGenMiddleConnection.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using System.Numerics;
  2. using System.Threading.Tasks;
  3. using Content.Shared.Maps;
  4. using Content.Shared.Procedural;
  5. using Content.Shared.Procedural.PostGeneration;
  6. using Content.Shared.Storage;
  7. using Robust.Shared.Utility;
  8. namespace Content.Server.Procedural.DungeonJob;
  9. public sealed partial class DungeonJob
  10. {
  11. /// <summary>
  12. /// <see cref="MiddleConnectionDunGen"/>
  13. /// </summary>
  14. private async Task PostGen(MiddleConnectionDunGen gen, DungeonData data, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
  15. {
  16. if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) ||
  17. !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entranceProto) ||
  18. !_prototype.TryIndex(entranceProto, out var entrance))
  19. {
  20. _sawmill.Error($"Tried to run {nameof(MiddleConnectionDunGen)} without any dungeon data set which is unsupported");
  21. return;
  22. }
  23. data.SpawnGroups.TryGetValue(DungeonDataKey.EntranceFlank, out var flankProto);
  24. _prototype.TryIndex(flankProto, out var flank);
  25. // Grab all of the room bounds
  26. // Then, work out connections between them
  27. var roomBorders = new Dictionary<DungeonRoom, HashSet<Vector2i>>(dungeon.Rooms.Count);
  28. foreach (var room in dungeon.Rooms)
  29. {
  30. var roomEdges = new HashSet<Vector2i>();
  31. foreach (var index in room.Tiles)
  32. {
  33. for (var x = -1; x <= 1; x++)
  34. {
  35. for (var y = -1; y <= 1; y++)
  36. {
  37. // Cardinals only
  38. if (x != 0 && y != 0 ||
  39. x == 0 && y == 0)
  40. {
  41. continue;
  42. }
  43. var neighbor = new Vector2i(index.X + x, index.Y + y);
  44. if (dungeon.RoomTiles.Contains(neighbor))
  45. continue;
  46. if (!_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
  47. continue;
  48. roomEdges.Add(neighbor);
  49. }
  50. }
  51. }
  52. roomBorders.Add(room, roomEdges);
  53. }
  54. // Do pathfind from first room to work out graph.
  55. // TODO: Optional loops
  56. var roomConnections = new Dictionary<DungeonRoom, List<DungeonRoom>>();
  57. var tileDef = _tileDefManager[tileProto];
  58. foreach (var (room, border) in roomBorders)
  59. {
  60. var conns = roomConnections.GetOrNew(room);
  61. foreach (var (otherRoom, otherBorders) in roomBorders)
  62. {
  63. if (room.Equals(otherRoom) ||
  64. conns.Contains(otherRoom))
  65. {
  66. continue;
  67. }
  68. var flipp = new HashSet<Vector2i>(border);
  69. flipp.IntersectWith(otherBorders);
  70. if (flipp.Count == 0 ||
  71. gen.OverlapCount != -1 && flipp.Count != gen.OverlapCount)
  72. continue;
  73. var center = Vector2.Zero;
  74. foreach (var node in flipp)
  75. {
  76. center += node + _grid.TileSizeHalfVector;
  77. }
  78. center /= flipp.Count;
  79. // Weight airlocks towards center more.
  80. var nodeDistances = new List<(Vector2i Node, float Distance)>(flipp.Count);
  81. foreach (var node in flipp)
  82. {
  83. nodeDistances.Add((node, (node + _grid.TileSizeHalfVector - center).LengthSquared()));
  84. }
  85. nodeDistances.Sort((x, y) => x.Distance.CompareTo(y.Distance));
  86. var width = gen.Count;
  87. for (var i = 0; i < nodeDistances.Count; i++)
  88. {
  89. var node = nodeDistances[i].Node;
  90. var gridPos = _maps.GridTileToLocal(_gridUid, _grid, node);
  91. if (!_anchorable.TileFree(_grid, node, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
  92. continue;
  93. width--;
  94. _maps.SetTile(_gridUid, _grid, node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
  95. if (flank != null && nodeDistances.Count - i <= 2)
  96. {
  97. _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(flank.Entries, random));
  98. }
  99. else
  100. {
  101. // Iterate neighbors and check for blockers, if so bulldoze
  102. ClearDoor(dungeon, _grid, node);
  103. _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(entrance.Entries, random));
  104. }
  105. if (width == 0)
  106. break;
  107. }
  108. conns.Add(otherRoom);
  109. var otherConns = roomConnections.GetOrNew(otherRoom);
  110. otherConns.Add(room);
  111. await SuspendDungeon();
  112. if (!ValidateResume())
  113. return;
  114. }
  115. }
  116. }
  117. }