Haunted dungeon template (#23768)

* haunted dungeon

* Initial work

Still needs prefab gen work to make it interesting.

* ime a worm

* weh

* Work

* Slight tweaks

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
Emisse
2024-03-23 21:37:18 -06:00
committed by GitHub
parent 2cc8db3007
commit 952b7f4c4e
17 changed files with 4009 additions and 67 deletions

View File

@@ -0,0 +1,53 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
namespace Content.Server.Procedural;
public sealed partial class DungeonJob
{
private async Task PostGen(CorridorClutterPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid,
Random random)
{
var physicsQuery = _entManager.GetEntityQuery<PhysicsComponent>();
var count = (int) Math.Ceiling(dungeon.CorridorTiles.Count * gen.Chance);
while (count > 0)
{
var tile = random.Pick(dungeon.CorridorTiles);
var enumerator = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile);
var blocked = false;
while (enumerator.MoveNext(out var ent))
{
if (!physicsQuery.TryGetComponent(ent, out var physics) ||
!physics.CanCollide ||
!physics.Hard)
{
continue;
}
blocked = true;
break;
}
if (blocked)
continue;
count--;
var protos = EntitySpawnCollection.GetSpawns(gen.Contents, random);
var coords = _maps.ToCenterCoordinates(_gridUid, tile, _grid);
_entManager.SpawnEntities(coords, protos);
await SuspendIfOutOfTime();
if (!ValidateResume())
return;
}
}
}

View File

@@ -26,7 +26,7 @@ public sealed partial class DungeonJob
private bool HasWall(MapGridComponent grid, Vector2i tile) private bool HasWall(MapGridComponent grid, Vector2i tile)
{ {
var anchored = grid.GetAnchoredEntitiesEnumerator(tile); var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile);
while (anchored.MoveNext(out var uid)) while (anchored.MoveNext(out var uid))
{ {
@@ -52,7 +52,7 @@ public sealed partial class DungeonJob
// Gather existing nodes // Gather existing nodes
foreach (var tile in allTiles) foreach (var tile in allTiles)
{ {
var anchored = grid.GetAnchoredEntitiesEnumerator(tile); var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile);
while (anchored.MoveNext(out var anc)) while (anchored.MoveNext(out var anc))
{ {
@@ -186,7 +186,9 @@ public sealed partial class DungeonJob
// - Tiles first // - Tiles first
foreach (var neighbor in dungeon.RoomExteriorTiles) foreach (var neighbor in dungeon.RoomExteriorTiles)
{ {
if (dungeon.RoomTiles.Contains(neighbor)) DebugTools.Assert(!dungeon.RoomTiles.Contains(neighbor));
if (dungeon.Entrances.Contains(neighbor))
continue; continue;
if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
@@ -265,7 +267,6 @@ public sealed partial class DungeonJob
Random random) Random random)
{ {
var physicsQuery = _entManager.GetEntityQuery<PhysicsComponent>(); var physicsQuery = _entManager.GetEntityQuery<PhysicsComponent>();
var tagQuery = _entManager.GetEntityQuery<TagComponent>();
foreach (var tile in dungeon.CorridorTiles) foreach (var tile in dungeon.CorridorTiles)
{ {
@@ -771,7 +772,7 @@ public sealed partial class DungeonJob
{ {
for (var y = -expansion; y <= expansion; y++) for (var y = -expansion; y <= expansion; y++)
{ {
var neighbor = new Vector2i(tile.X + x, tile.Y + y); var neighbor = new Vector2(tile.X + x, tile.Y + y).Floored();
if (dungeon.RoomTiles.Contains(neighbor) || if (dungeon.RoomTiles.Contains(neighbor) ||
dungeon.RoomExteriorTiles.Contains(neighbor) || dungeon.RoomExteriorTiles.Contains(neighbor) ||
@@ -817,6 +818,52 @@ public sealed partial class DungeonJob
return mod; return mod;
}); });
WidenCorridor(dungeon, gen.Width, corridorTiles);
var setTiles = new List<(Vector2i, Tile)>();
var tileDef = _prototype.Index(gen.Tile);
foreach (var tile in corridorTiles)
{
setTiles.Add((tile, _tile.GetVariantTile(tileDef, random)));
}
grid.SetTiles(setTiles);
dungeon.CorridorTiles.UnionWith(corridorTiles);
BuildCorridorExterior(dungeon);
}
private void BuildCorridorExterior(Dungeon dungeon)
{
var exterior = dungeon.CorridorExteriorTiles;
// Just ignore entrances or whatever for now.
foreach (var tile in dungeon.CorridorTiles)
{
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
var neighbor = new Vector2i(tile.X + x, tile.Y + y);
if (dungeon.CorridorTiles.Contains(neighbor) ||
dungeon.RoomExteriorTiles.Contains(neighbor) ||
dungeon.RoomTiles.Contains(neighbor) ||
dungeon.Entrances.Contains(neighbor))
{
continue;
}
exterior.Add(neighbor);
}
}
}
}
private void WidenCorridor(Dungeon dungeon, float width, ICollection<Vector2i> corridorTiles)
{
var expansion = width - 2;
// Widen the path // Widen the path
if (expansion >= 1) if (expansion >= 1)
{ {
@@ -831,7 +878,7 @@ public sealed partial class DungeonJob
{ {
for (var y = -expansion; y <= expansion; y++) for (var y = -expansion; y <= expansion; y++)
{ {
var neighbor = new Vector2i(node.X + x, node.Y + y); var neighbor = new Vector2(node.X + x, node.Y + y).Floored();
// Diagonals still matter here. // Diagonals still matter here.
if (dungeon.RoomTiles.Contains(neighbor) || if (dungeon.RoomTiles.Contains(neighbor) ||
@@ -852,36 +899,6 @@ public sealed partial class DungeonJob
corridorTiles.Add(node); corridorTiles.Add(node);
} }
} }
var setTiles = new List<(Vector2i, Tile)>();
var tileDef = _prototype.Index(gen.Tile);
foreach (var tile in corridorTiles)
{
setTiles.Add((tile, _tile.GetVariantTile(tileDef, random)));
}
grid.SetTiles(setTiles);
dungeon.CorridorTiles.UnionWith(corridorTiles);
var exterior = dungeon.CorridorExteriorTiles;
// Just ignore entrances or whatever for now.
foreach (var tile in dungeon.CorridorTiles)
{
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
var neighbor = new Vector2i(tile.X + x, tile.Y + y);
if (dungeon.CorridorTiles.Contains(neighbor))
continue;
exterior.Add(neighbor);
}
}
}
} }
private async Task PostGen(EntranceFlankPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, private async Task PostGen(EntranceFlankPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid,

View File

@@ -21,7 +21,6 @@ public sealed partial class DungeonJob
var dungeonRotation = _dungeon.GetDungeonRotation(seed); var dungeonRotation = _dungeon.GetDungeonRotation(seed);
var dungeonTransform = Matrix3.CreateTransform(_position, dungeonRotation); var dungeonTransform = Matrix3.CreateTransform(_position, dungeonRotation);
var roomPackProtos = new Dictionary<Vector2i, List<DungeonRoomPackPrototype>>(); var roomPackProtos = new Dictionary<Vector2i, List<DungeonRoomPackPrototype>>();
var fallbackTile = new Tile(_tileDefManager[prefab.Tile].TileId);
foreach (var pack in _prototype.EnumeratePrototypes<DungeonRoomPackPrototype>()) foreach (var pack in _prototype.EnumeratePrototypes<DungeonRoomPackPrototype>())
{ {
@@ -325,6 +324,7 @@ public sealed partial class DungeonJob
} }
room.Entrances.Add(entrancePos); room.Entrances.Add(entrancePos);
dungeon.Entrances.Add(entrancePos);
break; break;
} }
} }

View File

@@ -0,0 +1,193 @@
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural;
public sealed partial class DungeonJob
{
/// <summary>
/// Tries to connect rooms via worm-like corridors.
/// </summary>
private async Task PostGen(WormCorridorPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random)
{
var networks = new List<(Vector2i Start, HashSet<Vector2i> Network)>();
// List of places to start from.
var worm = new ValueList<Vector2i>();
var startAngles = new Dictionary<Vector2i, Angle>();
foreach (var room in dungeon.Rooms)
{
foreach (var entrance in room.Entrances)
{
var network = new HashSet<Vector2i> { entrance };
networks.Add((entrance, network));
// Point away from the room to start with.
startAngles.Add(entrance, (entrance + grid.TileSizeHalfVector - room.Center).ToAngle());
}
}
// There's a lot of ways to handle this, e.g. pathfinding towards each room
// For simplicity we'll go through each entrance randomly and generate worms from it
// then as a final step we will connect all of their networks.
random.Shuffle(networks);
for (var i = 0; i < gen.Count; i++)
{
// Find a random network to worm from.
var startIndex = (i % networks.Count);
var startPos = networks[startIndex].Start;
var position = startPos + grid.TileSizeHalfVector;
var remainingLength = gen.Length;
worm.Clear();
var angle = startAngles[startPos];
for (var x = remainingLength; x >= 0; x--)
{
position += angle.ToVec();
angle += random.NextAngle(-gen.MaxAngleChange, gen.MaxAngleChange);
var roundedPos = position.Floored();
// Check if the tile doesn't overlap something it shouldn't
if (dungeon.RoomTiles.Contains(roundedPos) ||
dungeon.RoomExteriorTiles.Contains(roundedPos))
{
continue;
}
worm.Add(roundedPos);
}
// Uhh yeah.
if (worm.Count == 0)
{
continue;
}
// Find a random part on the existing worm to start.
var value = random.Pick(worm);
networks[startIndex].Network.UnionWith(worm);
startAngles[value] = random.NextAngle();
}
// Now to ensure they all connect we'll pathfind each network to one another
// Simple BFS pathfinder
var main = networks[0];
var frontier = new PriorityQueue<Vector2i, float>();
var cameFrom = new Dictionary<Vector2i, Vector2i>();
var costSoFar = new Dictionary<Vector2i, float>();
// How many times we try to patch the networks together
var attempts = 3;
for (var attempt = 0; attempt < attempts; attempt++)
{
// Skip index 0
for (var i = networks.Count - 1; i > 0; i--)
{
cameFrom.Clear();
frontier.Clear();
costSoFar.Clear();
var targetNode = random.Pick(main.Network);
var other = networks[i];
var startNode = other.Network.First();
frontier.Enqueue(startNode, 0f);
costSoFar[startNode] = 0f;
var count = 0;
await SuspendIfOutOfTime();
if (!ValidateResume())
return;
while (frontier.TryDequeue(out var node, out _) && count < gen.PathLimit)
{
count++;
// Found
if (main.Network.Contains(node))
{
// found, rebuild
frontier.Clear();
main.Network.Add(node);
main.Network.UnionWith(other.Network);
var target = node;
// Rebuild
while (cameFrom.TryGetValue(target, out var source))
{
target = source;
main.Network.Add(target);
}
networks.RemoveSwap(i);
continue;
}
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
if (x == 0 && y == 0)
continue;
var neighbor = node + new Vector2i(x, y);
// Exclude room tiles.
if (dungeon.RoomTiles.Contains(neighbor) ||
dungeon.RoomExteriorTiles.Contains(neighbor))
{
continue;
}
var tileCost = (neighbor - node).Length;
var gScore = costSoFar[node] + tileCost;
if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue)
{
continue;
}
cameFrom[neighbor] = node;
costSoFar[neighbor] = gScore;
var hScore = (targetNode - neighbor).Length + gScore;
frontier.Enqueue(neighbor, hScore);
}
}
}
}
}
WidenCorridor(dungeon, gen.Width, main.Network);
dungeon.CorridorTiles.UnionWith(main.Network);
BuildCorridorExterior(dungeon);
var tiles = new List<(Vector2i Index, Tile Tile)>();
var tileDef = _prototype.Index(gen.Tile);
foreach (var tile in dungeon.CorridorTiles)
{
tiles.Add((tile, _tile.GetVariantTile(tileDef, random)));
}
foreach (var tile in dungeon.CorridorExteriorTiles)
{
tiles.Add((tile, _tile.GetVariantTile(tileDef, random)));
}
_maps.SetTiles(_gridUid, _grid, tiles);
}
}

View File

@@ -126,6 +126,9 @@ public sealed partial class DungeonJob : Job<Dungeon>
case CornerClutterPostGen clutter: case CornerClutterPostGen clutter:
await PostGen(clutter, dungeon, _gridUid, _grid, random); await PostGen(clutter, dungeon, _gridUid, _grid, random);
break; break;
case CorridorClutterPostGen corClutter:
await PostGen(corClutter, dungeon, _gridUid, _grid, random);
break;
case CorridorPostGen cordor: case CorridorPostGen cordor:
await PostGen(cordor, dungeon, _gridUid, _grid, random); await PostGen(cordor, dungeon, _gridUid, _grid, random);
break; break;
@@ -159,6 +162,9 @@ public sealed partial class DungeonJob : Job<Dungeon>
case WallMountPostGen wall: case WallMountPostGen wall:
await PostGen(wall, dungeon, _gridUid, _grid, random); await PostGen(wall, dungeon, _gridUid, _grid, random);
break; break;
case WormCorridorPostGen worm:
await PostGen(worm, dungeon, _gridUid, _grid, random);
break;
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@@ -15,6 +15,8 @@ public sealed class Dungeon
public readonly HashSet<Vector2i> CorridorExteriorTiles = new(); public readonly HashSet<Vector2i> CorridorExteriorTiles = new();
public readonly HashSet<Vector2i> Entrances = new();
public Dungeon() public Dungeon()
{ {
Rooms = new List<DungeonRoom>(); Rooms = new List<DungeonRoom>();
@@ -23,5 +25,10 @@ public sealed class Dungeon
public Dungeon(List<DungeonRoom> rooms) public Dungeon(List<DungeonRoom> rooms)
{ {
Rooms = rooms; Rooms = rooms;
foreach (var room in Rooms)
{
Entrances.UnionWith(room.Entrances);
}
} }
} }

View File

@@ -4,7 +4,7 @@ namespace Content.Shared.Procedural;
public sealed record DungeonRoom(HashSet<Vector2i> Tiles, Vector2 Center, Box2i Bounds, HashSet<Vector2i> Exterior) public sealed record DungeonRoom(HashSet<Vector2i> Tiles, Vector2 Center, Box2i Bounds, HashSet<Vector2i> Exterior)
{ {
public List<Vector2i> Entrances = new(); public readonly List<Vector2i> Entrances = new();
/// <summary> /// <summary>
/// Nodes adjacent to tiles, including the corners. /// Nodes adjacent to tiles, including the corners.

View File

@@ -9,15 +9,25 @@ namespace Content.Shared.Procedural.PostGeneration;
/// </summary> /// </summary>
public sealed partial class BoundaryWallPostGen : IPostDunGen public sealed partial class BoundaryWallPostGen : IPostDunGen
{ {
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))] [DataField]
public string Tile = "FloorSteel"; public ProtoId<ContentTileDefinition> Tile = "FloorSteel";
[DataField("wall", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))] [DataField]
public string Wall = "WallSolid"; public EntProtoId Wall = "WallSolid";
/// <summary> /// <summary>
/// Walls to use in corners if applicable. /// Walls to use in corners if applicable.
/// </summary> /// </summary>
[DataField("cornerWall", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))] [DataField]
public string? CornerWall; public string? CornerWall;
[DataField]
public BoundaryWallFlags Flags = BoundaryWallFlags.Corridors | BoundaryWallFlags.Rooms;
}
[Flags]
public enum BoundaryWallFlags : byte
{
Rooms = 1 << 0,
Corridors = 1 << 1,
} }

View File

@@ -7,12 +7,12 @@ namespace Content.Shared.Procedural.PostGeneration;
/// </summary> /// </summary>
public sealed partial class CornerClutterPostGen : IPostDunGen public sealed partial class CornerClutterPostGen : IPostDunGen
{ {
[DataField("chance")] [DataField]
public float Chance = 0.50f; public float Chance = 0.50f;
/// <summary> /// <summary>
/// The default starting bulbs /// The default starting bulbs
/// </summary> /// </summary>
[DataField("contents", required: true)] [DataField(required: true)]
public List<EntitySpawnEntry> Contents = new(); public List<EntitySpawnEntry> Contents = new();
} }

View File

@@ -0,0 +1,18 @@
using Content.Shared.Storage;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// Adds entities randomly to the corridors.
/// </summary>
public sealed partial class CorridorClutterPostGen : IPostDunGen
{
[DataField]
public float Chance = 0.05f;
/// <summary>
/// The default starting bulbs
/// </summary>
[DataField(required: true)]
public List<EntitySpawnEntry> Contents = new();
}

View File

@@ -14,24 +14,15 @@ public sealed partial class CorridorPostGen : IPostDunGen
/// <remarks> /// <remarks>
/// Given the heavy weightings this needs to be fairly large for larger dungeons. /// Given the heavy weightings this needs to be fairly large for larger dungeons.
/// </remarks> /// </remarks>
[DataField("pathLimit")] [DataField]
public int PathLimit = 2048; public int PathLimit = 2048;
[DataField("method")]
public CorridorPostGenMethod Method = CorridorPostGenMethod.MinimumSpanningTree;
[DataField] [DataField]
public ProtoId<ContentTileDefinition> Tile = "FloorSteel"; public ProtoId<ContentTileDefinition> Tile = "FloorSteel";
/// <summary> /// <summary>
/// How wide to make the corridor. /// How wide to make the corridor.
/// </summary> /// </summary>
[DataField("width")] [DataField]
public int Width = 3; public float Width = 3f;
}
public enum CorridorPostGenMethod : byte
{
Invalid,
MinimumSpanningTree,
} }

View File

@@ -0,0 +1,42 @@
using Content.Shared.Maps;
using Content.Shared.Procedural.DungeonGenerators;
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural.PostGeneration;
// Ime a worm
/// <summary>
/// Generates worm corridors.
/// </summary>
public sealed partial class WormCorridorPostGen : IPostDunGen
{
[DataField]
public int PathLimit = 2048;
/// <summary>
/// How many times to run the worm
/// </summary>
[DataField]
public int Count = 20;
/// <summary>
/// How long to make each worm
/// </summary>
[DataField]
public int Length = 20;
/// <summary>
/// Maximum amount the angle can change in a single step.
/// </summary>
[DataField]
public Angle MaxAngleChange = Angle.FromDegrees(45);
[DataField]
public ProtoId<ContentTileDefinition> Tile = "FloorSteel";
/// <summary>
/// How wide to make the corridor.
/// </summary>
[DataField]
public float Width = 3f;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,308 @@
# Rooms
# Large
# - 17x5
- type: dungeonRoom
id: Haunted17x5a
size: 17,5
atlas: /Maps/Dungeon/haunted.yml
offset: 0,0
tags:
- Haunted
- type: dungeonRoom
id: Haunted17x5b
size: 17,5
atlas: /Maps/Dungeon/haunted.yml
offset: 18,0
tags:
- Haunted
# - 7x7
- type: dungeonRoom
id: Haunted7x7a
size: 7,7
atlas: /Maps/Dungeon/haunted.yml
offset: 0,42
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x7b
size: 7,7
atlas: /Maps/Dungeon/haunted.yml
offset: 8,42
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x7c
size: 7,7
atlas: /Maps/Dungeon/haunted.yml
offset: 16,42
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x7d
size: 7,7
atlas: /Maps/Dungeon/haunted.yml
offset: 24,42
tags:
- Haunted
# Medium
# - 11x5
- type: dungeonRoom
id: Haunted11x5a
size: 11,5
atlas: /Maps/Dungeon/haunted.yml
offset: 0,6
tags:
- Haunted
- type: dungeonRoom
id: Haunted11x5b
size: 11,5
atlas: /Maps/Dungeon/haunted.yml
offset: 12,6
tags:
- Haunted
- type: dungeonRoom
id: Haunted11x5c
size: 11,5
atlas: /Maps/Dungeon/haunted.yml
offset: 24,6
tags:
- Haunted
# - 7x5
- type: dungeonRoom
id: Haunted7x5a
size: 7,5
atlas: /Maps/Dungeon/haunted.yml
offset: 0,12
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x5b
size: 7,5
atlas: /Maps/Dungeon/haunted.yml
offset: 8,12
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x5c
size: 7,5
atlas: /Maps/Dungeon/haunted.yml
offset: 16,12
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x5d
size: 7,5
atlas: /Maps/Dungeon/haunted.yml
offset: 24,12
tags:
- Haunted
# - 13x3
- type: dungeonRoom
id: Haunted13x3a
size: 13,3
atlas: /Maps/Dungeon/haunted.yml
offset: 0,30
tags:
- Haunted
- type: dungeonRoom
id: Haunted13x3b
size: 13,3
atlas: /Maps/Dungeon/haunted.yml
offset: 14,30
tags:
- Haunted
# - 11x3
- type: dungeonRoom
id: Haunted11x3a
size: 11,3
atlas: /Maps/Dungeon/haunted.yml
offset: 0,34
tags:
- Haunted
- type: dungeonRoom
id: Haunted11x3b
size: 11,3
atlas: /Maps/Dungeon/haunted.yml
offset: 12,34
tags:
- Haunted
- type: dungeonRoom
id: Haunted11x3c
size: 11,3
atlas: /Maps/Dungeon/haunted.yml
offset: 24,34
tags:
- Haunted
# - 7x3
- type: dungeonRoom
id: Haunted7x3a
size: 7,3
atlas: /Maps/Dungeon/haunted.yml
offset: 0,38
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x3b
size: 7,3
atlas: /Maps/Dungeon/haunted.yml
offset: 8,38
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x3c
size: 7,3
atlas: /Maps/Dungeon/haunted.yml
offset: 16,38
tags:
- Haunted
- type: dungeonRoom
id: Haunted7x3d
size: 7,3
atlas: /Maps/Dungeon/haunted.yml
offset: 24,38
tags:
- Haunted
# Small
# - 5x5
- type: dungeonRoom
id: Haunted5x5a
size: 5,5
atlas: /Maps/Dungeon/haunted.yml
offset: 0,18
tags:
- Haunted
- type: dungeonRoom
id: Haunted5x5b
size: 5,5
atlas: /Maps/Dungeon/haunted.yml
offset: 6,18
tags:
- Haunted
- type: dungeonRoom
id: Haunted5x5c
size: 5,5
atlas: /Maps/Dungeon/haunted.yml
offset: 12,18
tags:
- Haunted
- type: dungeonRoom
id: Haunted5x5d
size: 5,5
atlas: /Maps/Dungeon/haunted.yml
offset: 18,18
tags:
- Haunted
- type: dungeonRoom
id: Haunted5x5e
size: 5,5
atlas: /Maps/Dungeon/haunted.yml
offset: 24,18
tags:
- Haunted
- type: dungeonRoom
id: Haunted5x5f
size: 5,5
atlas: /Maps/Dungeon/haunted.yml
offset: 30,18
tags:
- Haunted
# - 3x5
- type: dungeonRoom
id: Haunted3x5a
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 0,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5b
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 4,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5c
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 8,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5d
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 12,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5e
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 16,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5f
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 20,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5g
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 24,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5h
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 28,24
tags:
- Haunted
- type: dungeonRoom
id: Haunted3x5i
size: 3,5
atlas: /Maps/Dungeon/haunted.yml
offset: 32,24
tags:
- Haunted

View File

@@ -175,15 +175,15 @@
- SpaceShip - SpaceShip
- Tall - Tall
postGeneration: postGeneration:
- !type:CorridorPostGen - !type:CorridorPostGen
tile: FloorCaveDrought tile: FloorCaveDrought
width: 3 width: 3
- !type:DungeonEntrancePostGen - !type:DungeonEntrancePostGen
count: 5 count: 5
tile: FloorCaveDrought tile: FloorCaveDrought
entities: entities:
- RandomWoodenWall - RandomWoodenWall
- !type:RoomEntrancePostGen - !type:RoomEntrancePostGen
@@ -195,12 +195,12 @@
tile: FloorCaveDrought tile: FloorCaveDrought
entities: entities:
- RandomWoodenWall - RandomWoodenWall
- !type:ExternalWindowPostGen - !type:ExternalWindowPostGen
tile: FloorCaveDrought tile: FloorCaveDrought
entities: entities:
- RandomWoodenWall - RandomWoodenWall
- !type:WallMountPostGen - !type:WallMountPostGen
tile: FloorCaveDrought tile: FloorCaveDrought
spawns: spawns:
@@ -217,7 +217,7 @@
- id: WallMining - id: WallMining
prob: 0.8 prob: 0.8
orGroup: content orGroup: content
- !type:BoundaryWallPostGen - !type:BoundaryWallPostGen
tile: FloorCaveDrought tile: FloorCaveDrought
wall: WallRock wall: WallRock
@@ -225,13 +225,13 @@
- !type:AutoCablingPostGen - !type:AutoCablingPostGen
entity: Catwalk entity: Catwalk
- !type:JunctionPostGen - !type:JunctionPostGen
tile: FloorCaveDrought tile: FloorCaveDrought
width: 3 width: 3
entities: entities:
- RandomWoodenSupport - RandomWoodenSupport
- !type:CornerClutterPostGen - !type:CornerClutterPostGen
contents: contents:
- id: RandomStalagmiteOrCrystal - id: RandomStalagmiteOrCrystal
@@ -321,4 +321,41 @@
SouthWest: BrickTileWhiteInnerSw SouthWest: BrickTileWhiteInnerSw
SouthEast: BrickTileWhiteInnerSe SouthEast: BrickTileWhiteInnerSe
NorthWest: BrickTileWhiteInnerNw NorthWest: BrickTileWhiteInnerNw
NorthEast: BrickTileWhiteInnerNe NorthEast: BrickTileWhiteInnerNe
# todo: Add a biome dungeon generator
# Add corridor first gens that place rooms on top
# Add a worm corridor gen (place subsequent corridors somewhere randomly along the path)
# Place room entrances on ends of corridors touching a tile
# Remove all room tiles from corridors
# Fix paths up and try to reconnect all corridor tiles
# Add a postgen step to spread rooms out, though it shouldn't spread into corridor exteriors
- type: dungeonConfig
id: Haunted
generator: !type:PrefabDunGen
tile: FloorCaveDrought
roomWhitelist:
- Mineshaft
presets:
- Bucket
- Wow
- SpaceShip
- Tall
postGeneration:
- !type:WormCorridorPostGen
width: 3
tile: FloorCaveDrought
- !type:CorridorClutterPostGen
contents:
- id: FloraStalagmite1
- id: FloraStalagmite2
- id: FloraStalagmite3
- id: FloraStalagmite4
- id: FloraStalagmite5
- id: FloraStalagmite6
- !type:BoundaryWallPostGen
tile: FloorCaveDrought
wall: WallRock

View File

@@ -241,4 +241,10 @@
id: SnowyLabs id: SnowyLabs
proto: SnowyLabs proto: SnowyLabs
biomes: biomes:
- Snow - Snow
- type: salvageDungeonMod
id: Haunted
proto: Haunted
biomes:
- Caves

View File

@@ -673,6 +673,9 @@
- type: Tag - type: Tag
id: Hardsuit # Prevent melee injectors that can't penetrate hardsuits from injecting the wearer (nettles) id: Hardsuit # Prevent melee injectors that can't penetrate hardsuits from injecting the wearer (nettles)
- type: Tag
id: Haunted
- type: Tag - type: Tag
id: Head id: Head