1
0

DungeonJob.PostGenInternalWindow.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. namespace Content.Server.Procedural.DungeonJob;
  8. public sealed partial class DungeonJob
  9. {
  10. /// <summary>
  11. /// <see cref="InternalWindowDunGen"/>
  12. /// </summary>
  13. private async Task PostGen(InternalWindowDunGen 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.Window, out var windowGroup))
  17. {
  18. _sawmill.Error($"Unable to find dungeon data keys for {nameof(gen)}");
  19. return;
  20. }
  21. // Iterate every room and check if there's a gap beyond it that leads to another room within N tiles
  22. // If so then consider windows
  23. var minDistance = 4;
  24. var maxDistance = 6;
  25. var tileDef = _tileDefManager[tileProto];
  26. var window = _prototype.Index(windowGroup);
  27. foreach (var room in dungeon.Rooms)
  28. {
  29. var validTiles = new List<Vector2i>();
  30. for (var i = 0; i < 4; i++)
  31. {
  32. var dir = (DirectionFlag) Math.Pow(2, i);
  33. var dirVec = dir.AsDir().ToIntVec();
  34. foreach (var tile in room.Tiles)
  35. {
  36. var tileAngle = (tile + _grid.TileSizeHalfVector - room.Center).ToAngle();
  37. var roundedAngle = Math.Round(tileAngle.Theta / (Math.PI / 2)) * (Math.PI / 2);
  38. var tileVec = (Vector2i) new Angle(roundedAngle).ToVec().Rounded();
  39. if (!tileVec.Equals(dirVec))
  40. continue;
  41. var valid = false;
  42. for (var j = 1; j < maxDistance; j++)
  43. {
  44. var edgeNeighbor = tile + dirVec * j;
  45. if (dungeon.RoomTiles.Contains(edgeNeighbor))
  46. {
  47. if (j < minDistance)
  48. {
  49. valid = false;
  50. }
  51. else
  52. {
  53. valid = true;
  54. }
  55. break;
  56. }
  57. }
  58. if (!valid)
  59. continue;
  60. var windowTile = tile + dirVec;
  61. if (reservedTiles.Contains(windowTile))
  62. continue;
  63. if (!_anchorable.TileFree(_grid, windowTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
  64. continue;
  65. validTiles.Add(windowTile);
  66. }
  67. validTiles.Sort((x, y) => (x + _grid.TileSizeHalfVector - room.Center).LengthSquared().CompareTo((y + _grid.TileSizeHalfVector - room.Center).LengthSquared()));
  68. for (var j = 0; j < Math.Min(validTiles.Count, 3); j++)
  69. {
  70. var tile = validTiles[j];
  71. var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile);
  72. _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
  73. _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(window.Entries, random));
  74. }
  75. if (validTiles.Count > 0)
  76. {
  77. await SuspendDungeon();
  78. if (!ValidateResume())
  79. return;
  80. }
  81. validTiles.Clear();
  82. }
  83. }
  84. }
  85. }