protected virtual bool AttemptBlob(T map, BlobMap blobMap, int blobIdx) { Rect blobRect = blobMap.Blobs[blobIdx].Bounds; Loc offset = new Loc(map.Rand.Next(0, map.Width - blobRect.Width), map.Rand.Next(0, map.Height - blobRect.Height)); this.DrawBlob(map, blobMap, blobIdx, offset, false); return(true); }
public override void Apply(T map) { int blobs = this.Blobs.Pick(map.Rand); int startScale = Math.Max(this.MinScale, this.StartScale.Pick(map.Rand)); for (int ii = 0; ii < blobs; ii++) { Loc size = new Loc(map.Width * startScale / 100, map.Height * startScale / 100); int area = size.X * size.Y; bool placed = false; while (area > 0 && area >= this.MinScale * map.Width / 100 * this.MinScale * map.Height / 100) { bool[][] noise = new bool[size.X][]; for (int xx = 0; xx < size.X; xx++) { noise[xx] = new bool[size.Y]; for (int yy = 0; yy < size.Y; yy++) { noise[xx][yy] = map.Rand.Next(100) < AUTOMATA_CHANCE; } } noise = NoiseGen.IterateAutomata(noise, CellRule.Gte5, CellRule.Gte4, AUTOMATA_ROUNDS); bool IsWaterValid(Loc loc) => noise[loc.X][loc.Y]; BlobMap blobMap = Detection.DetectBlobs(new Rect(0, 0, noise.Length, noise[0].Length), IsWaterValid); if (blobMap.Blobs.Count > 0) { int blobIdx = 0; for (int bb = 1; bb < blobMap.Blobs.Count; bb++) { if (blobMap.Blobs[bb].Area > blobMap.Blobs[blobIdx].Area) { blobIdx = bb; } } placed = this.AttemptBlob(map, blobMap, blobIdx); } if (placed) { break; } size = size * 7 / 10; area = size.X * size.Y; } } }
protected override bool AttemptBlob(T map, BlobMap blobMap, int blobIdx) { bool IsMapValid(Loc loc) => map.GetTile(loc).TileEquivalent(map.RoomTerrain); // the XY to add to translate from point on the map to point on the blob map Loc offset = Loc.Zero; bool IsBlobValid(Loc loc) { Loc srcLoc = loc + blobMap.Blobs[blobIdx].Bounds.Start; if (!Collision.InBounds(blobMap.Blobs[blobIdx].Bounds, srcLoc)) { return(false); } Loc destLoc = loc + offset; if (!map.CanSetTile(destLoc, this.Terrain)) { return(false); } return(blobMap.Map[srcLoc.X][srcLoc.Y] == blobIdx); } // attempt to place in 20 locations for (int jj = 0; jj < 20; jj++) { Rect blobRect = blobMap.Blobs[blobIdx].Bounds; offset = new Loc(map.Rand.Next(0, map.Width - blobRect.Width), map.Rand.Next(0, map.Height - blobRect.Height)); Loc blobMod = blobMap.Blobs[blobIdx].Bounds.Start - offset; // pass this into the walkable detection function bool disconnects = Detection.DetectDisconnect(new Rect(0, 0, map.Width, map.Height), IsMapValid, offset, blobRect.Size, IsBlobValid, true); // if it's a pass, draw on tile if it's a wall terrain or a room terrain if (disconnects) { continue; } this.DrawBlob(map, blobMap, blobIdx, offset, true); return(true); } return(false); }
protected void DrawBlob(T map, BlobMap blobMap, int index, Loc offset, bool encroach) { BlobMap.Blob mapBlob = blobMap.Blobs[index]; for (int xx = Math.Max(0, offset.X); xx < Math.Min(map.Width, offset.X + mapBlob.Bounds.Width); xx++) { for (int yy = Math.Max(0, offset.Y); yy < Math.Min(map.Height, offset.Y + mapBlob.Bounds.Height); yy++) { Loc destLoc = new Loc(xx, yy); Loc srcLoc = destLoc + mapBlob.Bounds.Start - offset; if (blobMap.Map[srcLoc.X][srcLoc.Y] == index) { // can place anything if encroaching // otherwise, can place anything except roomterrain if (encroach || !map.GetTile(destLoc).TileEquivalent(map.RoomTerrain)) { map.TrySetTile(new Loc(xx, yy), this.Terrain.Copy()); } } } } GenContextDebug.DebugProgress("Draw Blob"); }
public static BlobMap DetectBlobs(Rect rect, Grid.LocTest isValid) { if (isValid == null) { throw new ArgumentNullException(nameof(isValid)); } var blobMap = new BlobMap(rect.Width, rect.Height); for (int xx = rect.X; xx < rect.End.X; xx++) { for (int yy = rect.Y; yy < rect.End.Y; yy++) { if (isValid(new Loc(xx, yy)) && blobMap.Map[xx][yy] == -1) { var blob = new BlobMap.Blob(new Rect(xx, yy, 1, 1), 0); // fill the area, keeping track of the total area and blob bounds Grid.FloodFill( rect, (Loc testLoc) => (!isValid(testLoc) || blobMap.Map[testLoc.X][testLoc.Y] != -1), (Loc testLoc) => true, (Loc fillLoc) => { blobMap.Map[fillLoc.X][fillLoc.Y] = blobMap.Blobs.Count; blob.Bounds = Rect.IncludeLoc(blob.Bounds, fillLoc); blob.Area += 1; }, new Loc(xx, yy)); blobMap.Blobs.Add(blob); } } } return(blobMap); }
public override void Apply(T map) { int waterPercent = this.WaterPercent.Pick(map.Rand); if (waterPercent == 0) { return; } int depthRange = 0x1 << (this.OrderComplexity + this.OrderSoftness); // aka, 2 ^ degree int minWater = waterPercent * map.Width * map.Height / 100; int[][] noise = NoiseGen.PerlinNoise(map.Rand, map.Width, map.Height, this.OrderComplexity, this.OrderSoftness); int[] depthCount = new int[depthRange]; for (int xx = 0; xx < map.Width; xx++) { for (int yy = 0; yy < map.Height; yy++) { depthCount[noise[xx][yy]]++; } } int waterMark = 0; int totalDepths = 0; for (int ii = 0; ii < depthCount.Length; ii++) { if (totalDepths + depthCount[ii] >= minWater) { if (totalDepths + depthCount[ii] - minWater < minWater - totalDepths) { waterMark++; } break; } totalDepths += depthCount[ii]; waterMark++; } if (this.RespectFloor) { this.DrawWhole(map, noise, depthRange, waterMark); return; } while (waterMark > 0) { bool IsWaterValid(Loc loc) { int heightPercent = Math.Min(100, Math.Min(Math.Min(loc.X * 100 / BUFFER_SIZE, loc.Y * 100 / BUFFER_SIZE), Math.Min((map.Width - 1 - loc.X) * 100 / BUFFER_SIZE, (map.Height - 1 - loc.Y) * 100 / BUFFER_SIZE))); int noiseVal = (noise[loc.X][loc.Y] * heightPercent / 100) + (depthRange * (100 - heightPercent) / 100); return(noiseVal < waterMark); } BlobMap blobMap = Detection.DetectBlobs(new Rect(0, 0, map.Width, map.Height), IsWaterValid); bool IsMapValid(Loc loc) => map.GetTile(loc).TileEquivalent(map.RoomTerrain); int blobIdx = 0; bool IsBlobValid(Loc loc) { Loc srcLoc = loc + blobMap.Blobs[blobIdx].Bounds.Start; if (!map.CanSetTile(srcLoc, this.Terrain)) { return(false); } return(blobMap.Map[srcLoc.X][srcLoc.Y] == blobIdx); } for (; blobIdx < blobMap.Blobs.Count; blobIdx++) { Rect blobRect = blobMap.Blobs[blobIdx].Bounds; // pass this into the walkable detection function bool disconnects = Detection.DetectDisconnect(new Rect(0, 0, map.Width, map.Height), IsMapValid, blobRect.Start, blobRect.Size, IsBlobValid, true); // if it's a pass, draw on tile if it's a wall terrain or a room terrain if (!disconnects) { this.DrawBlob(map, blobMap, blobIdx, blobRect.Start, true); } else { // if it's a fail, draw on the tile only if wall terrain this.DrawBlob(map, blobMap, blobIdx, blobRect.Start, false); } } waterMark -= Math.Max(1, depthRange / 8); } }