protected LocRay4?PlaceRoom(T map, List <LocRay4> rays, EffectTile sealingTile, List <Loc> freeTiles) { Grid.LocTest checkBlockForPlace = (Loc testLoc) => { if (!Collision.InBounds(map.Width, map.Height, testLoc)) { return(false); } return(!map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.RoomTerrain) && !map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.UnbreakableTerrain)); }; //try X times to dig a passage for (int ii = 0; ii < 500 && rays.Count > 0; ii++) { int rayIndex = map.Rand.Next(rays.Count); LocRay4 ray = rays[rayIndex]; rays.RemoveAt(rayIndex); Loc rayDirLoc = ray.Dir.GetLoc(); Axis4 axis = ray.Dir.ToAxis(); Axis4 orth = axis == Axis4.Horiz ? Axis4.Vert : Axis4.Horiz; int minLength = Math.Max(1, HallLength.Min); Rect hallBound = new Rect(ray.Loc + DirExt.AddAngles(ray.Dir, Dir4.Left).GetLoc(), new Loc(1)); hallBound = Rect.IncludeLoc(hallBound, ray.Loc + rayDirLoc * (minLength - 1) + DirExt.AddAngles(ray.Dir, Dir4.Right).GetLoc()); //make sure the MIN hall can tunnel unimpeded if (!CanPlaceRect(map, hallBound, checkBlockForPlace)) { continue; } for (int jj = 0; jj < 100; jj++) { //plan the room RoomGen <T> plan = GenericRooms.Pick(map.Rand).Copy(); Loc size = plan.ProposeSize(map.Rand); plan.PrepareSize(map.Rand, size); //attempt to place the bounds somewhere, anywhere, within the limitations that the room itself provides List <int> candidateOpenings = new List <int>(); int planLength = plan.GetBorderLength(ray.Dir.Reverse()); for (int kk = 0; kk < planLength; kk++) { if (plan.GetFulfillableBorder(ray.Dir.Reverse(), kk)) { candidateOpenings.Add(kk); } } //as well as continue extending the hall until we hit a walkable. int tunnelLen = Math.Max(1, HallLength.Pick(map.Rand)); Loc roomLoc = ray.Loc + rayDirLoc * tunnelLen; int perpOffset = candidateOpenings[map.Rand.Next(candidateOpenings.Count)]; roomLoc += orth.CreateLoc(-perpOffset, 0); if (rayDirLoc.GetScalar(axis) < 0)//move back the top-left of the entrance { roomLoc += rayDirLoc * (size.GetScalar(axis) - 1); } Rect roomTestBound = new Rect(roomLoc, size); roomTestBound.Inflate(1, 1); //make a rect for the rest of the hall Rect hallExtBound = new Rect(ray.Loc + rayDirLoc * minLength + DirExt.AddAngles(ray.Dir, Dir4.Left).GetLoc(), new Loc(1)); hallExtBound = Rect.IncludeLoc(hallBound, ray.Loc + rayDirLoc * (tunnelLen - 1) + DirExt.AddAngles(ray.Dir, Dir4.Right).GetLoc()); //now that we've chosen our position, let's test it if (!CanPlaceRect(map, roomTestBound, checkBlockForPlace) || !CanPlaceRect(map, hallExtBound, checkBlockForPlace)) // also test that the CHOSEN hallway can be properly sealed { continue; //invalid location, try another place } else { plan.SetLoc(roomLoc); plan.ReceiveBorderRange(new IntRange(perpOffset, perpOffset + 1) + roomLoc.GetScalar(orth), ray.Dir.Reverse()); //draw the room plan.DrawOnMap(map); //surround the room with bounds for (int xx = roomTestBound.X; xx < roomTestBound.Right; xx++) { map.Tiles[xx][roomTestBound.Y] = (Tile)map.UnbreakableTerrain.Copy(); map.Tiles[xx][roomTestBound.End.Y - 1] = (Tile)map.UnbreakableTerrain.Copy(); } for (int yy = roomTestBound.Y + 1; yy < roomTestBound.Bottom - 1; yy++) { map.Tiles[roomTestBound.X][yy] = (Tile)map.UnbreakableTerrain.Copy(); map.Tiles[roomTestBound.End.X - 1][yy] = (Tile)map.UnbreakableTerrain.Copy(); } //spawn tiles, items, foes List <Loc> addedTiles = ((IPlaceableGenContext <MapItem>)map).GetFreeTiles(plan.Draw); freeTiles.AddRange(addedTiles); //tunnel to the room Loc loc = ray.Loc; for (int tt = 0; tt < tunnelLen; tt++) { //make walkable map.Tiles[loc.X][loc.Y] = (Tile)map.RoomTerrain.Copy(); //make left side unbreakable Loc lLoc = loc + DirExt.AddAngles(ray.Dir, Dir4.Left).GetLoc(); map.Tiles[lLoc.X][lLoc.Y] = (Tile)map.UnbreakableTerrain.Copy(); //make right side unbreakable Loc rLoc = loc + DirExt.AddAngles(ray.Dir, Dir4.Right).GetLoc(); map.Tiles[rLoc.X][rLoc.Y] = (Tile)map.UnbreakableTerrain.Copy(); loc += rayDirLoc; } //finally, seal with a locked door map.Tiles[ray.Loc.X][ray.Loc.Y] = (Tile)map.UnbreakableTerrain.Copy(); EffectTile newEffect = new EffectTile(sealingTile, ray.Loc); ((IPlaceableGenContext <EffectTile>)map).PlaceItem(ray.Loc, newEffect); return(ray); } } } //DiagManager.Instance.LogInfo("Couldn't place sealed detour!"); return(null); }