private GenChunkAddedStatus GenAddChunk(Random rand, Stack <GenEndPoint> endPoints, List <GenEndPoint> looseEnds, List <GenChunkRect> rects, ChunkTemplate[] templates, ref int area, int maxDepth = 0, bool first = false) { ChunkTemplate template; Chunk newChunk; List <GenEndPoint> endsToAdd; if (first) { template = templates[rand.Next(templates.Length)]; newChunk = new Chunk(0, 0, template, this); Chunks.Add(newChunk); endsToAdd = new List <GenEndPoint>(); for (int i = 0; i < 4; ++i) { foreach (ChunkConnector connector in template.GetConnectors((ConnectorFace)i)) { endsToAdd.Add(new GenEndPoint(newChunk, connector, 0)); } } while (endsToAdd.Count > 0) { int index = rand.Next(endsToAdd.Count); endPoints.Push(endsToAdd[index]); endsToAdd.RemoveAt(index); } rects.Add(new GenChunkRect(newChunk)); area += newChunk.Area; return(GenChunkAddedStatus.Added); } List <ChunkTemplate> validTemplates = new List <ChunkTemplate>(); GenEndPoint endPoint = endPoints.Pop(); ConnectorFace oppositeFace = (ConnectorFace)(((int)endPoint.Face + 2) % 4); foreach (ChunkTemplate temp in templates) { if (temp.GetConnectors(oppositeFace, endPoint.Size, endPoint.Skin).Length != 0) { validTemplates.Add(temp); } } if (validTemplates.Count == 0) { endPoints.Push(endPoint); return(GenChunkAddedStatus.ImpossibleToAdd); } template = validTemplates[rand.Next(validTemplates.Count)]; ChunkConnector[] cons = template.GetConnectors(oppositeFace, endPoint.Size, endPoint.Skin); if (cons.Length == 0) { endPoints.Push(endPoint); return(GenChunkAddedStatus.NotAdded); } ChunkConnector con = cons[rand.Next(cons.Length)]; int x = endPoint.X - con.X; int y = endPoint.Y - con.Y; switch (endPoint.Face) { case ConnectorFace.Left: --x; break; case ConnectorFace.Top: --y; break; case ConnectorFace.Right: ++x; break; case ConnectorFace.Bottom: ++y; break; } GenChunkRect newRect = new GenChunkRect(x, y, template); foreach (GenChunkRect rect in rects) { if (rect.Intersects(newRect)) { endPoints.Push(endPoint); return(GenChunkAddedStatus.NotAdded); } } newChunk = new Chunk(x, y, template, this); Chunks.Add(newChunk); endsToAdd = new List <GenEndPoint>(); for (int i = 0; i < 4; ++i) { foreach (ChunkConnector connector in template.GetConnectors((ConnectorFace)i)) { if (connector.X != con.X || connector.Y != con.Y) { GenEndPoint end = new GenEndPoint(newChunk, connector, endPoint.Depth + 1); if (maxDepth != 0 && endPoint.Depth >= maxDepth) { looseEnds.Add(end); } else { endsToAdd.Add(end); } } } } while (endsToAdd.Count > 0) { int index = rand.Next(endsToAdd.Count); endPoints.Push(endsToAdd[index]); endsToAdd.RemoveAt(index); } rects.Add(newRect); area += newChunk.Area; return(GenChunkAddedStatus.Added); }
public void Generate(uint seed = 0) { Random rand = seed == 0 ? new Random() : new Random((int)seed); int area = 0; int areaGoal = rand.Next(DungeonClass.AreaMin, DungeonClass.AreaMax); int maxDepth = (int)Math.Pow(areaGoal, 1 / 3) + 16; ChunkTemplate[] templates = DungeonClass.ChunkTemplates; Stack <GenEndPoint> endPoints = new Stack <GenEndPoint>(); List <GenEndPoint> looseEnds = new List <GenEndPoint>(); List <GenChunkRect> rects = new List <GenChunkRect>(); GenAddChunk(rand, endPoints, looseEnds, rects, templates, ref area, 0, true); int tries = 0; while (endPoints.Count > 0) { if (tries < 64 && area < areaGoal) { switch (GenAddChunk(rand, endPoints, looseEnds, rects, templates, ref area, maxDepth)) { case GenChunkAddedStatus.Added: tries = 0; break; case GenChunkAddedStatus.NotAdded: ++tries; break; case GenChunkAddedStatus.ImpossibleToAdd: tries = 64; break; } } else { looseEnds.Add(endPoints.Pop()); tries = 0; } } for (int i = looseEnds.Count - 1; i >= 0; --i) { GenEndPoint end = looseEnds[i]; bool horizontal = end.Face == ConnectorFace.Left || end.Face == ConnectorFace.Right; bool matchFound = false; for (int j = i - 1; j >= 0; --j) { GenEndPoint match = looseEnds[j]; if (end.Size == match.Size && end.Skin == match.Skin && ((int)match.Face ^ (int)end.Face) == 0x2 && ((horizontal && end.Y == match.Y && (end.X + 1 == match.X || end.X == match.X + 1)) || (!horizontal && end.X == match.X && (end.Y + 1 == match.Y || end.Y == match.Y + 1)))) { looseEnds.RemoveAt(i--); looseEnds.RemoveAt(j); matchFound = true; break; } } if (!matchFound) { for (int j = 0; j < end.Size; ++j) { end.Chunk.GetTile( end.X + (!horizontal ? j : 0), end.Y + (horizontal ? j : 0)).IsWall = true; } } } PostWorldInitialize(); myHasGenerated = true; }