public override void ApplyToPath(IRandom rand, GridPlan floorPlan) { int chosenBigRooms = RoomAmount.Pick(rand); for (int ii = 0; ii < chosenBigRooms; ii++) { for (int jj = 0; jj < 20; jj++) { LargeRoom <T> chosenRoom = GiantRooms.Pick(rand); Rect destRect = new Rect(new Loc(rand.Next(floorPlan.GridWidth - chosenRoom.Size.X), rand.Next(floorPlan.GridHeight - chosenRoom.Size.Y)), chosenRoom.Size); if (spaceViable(floorPlan, destRect)) { List <LocRay4> raysOut = new List <LocRay4>(); for (int xx = destRect.Start.X; xx < destRect.End.X; xx++) { LocRay4 locUp = new LocRay4(xx, destRect.Start.Y, Dir4.Up); if (destRect.Start.Y > 0 && floorPlan.GetHall(locUp) != null) { raysOut.Add(locUp); } LocRay4 locDown = new LocRay4(xx, destRect.Start.Y + chosenRoom.Size.Y - 1, Dir4.Down); if (destRect.Start.Y < floorPlan.GridHeight - 1 && floorPlan.GetHall(locDown) != null) { raysOut.Add(locDown); } } for (int yy = destRect.Start.Y; yy < destRect.End.Y; yy++) { LocRay4 locLeft = new LocRay4(destRect.Start.X, yy, Dir4.Left); if (destRect.Start.X > 0 && floorPlan.GetHall(locLeft) != null) { raysOut.Add(locLeft); } LocRay4 locRight = new LocRay4(destRect.Start.X + chosenRoom.Size.X - 1, yy, Dir4.Right); if (destRect.Start.X < floorPlan.GridWidth - 1 && floorPlan.GetHall(locRight) != null) { raysOut.Add(locRight); } } List <List <LocRay4> > exitSets = findHallSets(floorPlan, destRect, raysOut); //exits: no more than allowed if (exitSets.Count > chosenRoom.AllowedEntrances) { continue; } //this block tallies all sets that can be joined to the big room //it also chooses which ones to keep by randomly removing them from the raysOut list int setsTaken = 0; foreach (List <LocRay4> set in exitSets) { List <LocRay4> possibleRays = new List <LocRay4>(); foreach (LocRay4 ray in set) { int scalar = (ray.Loc - destRect.Start).GetScalar(ray.Dir.ToAxis().Orth()); if (chosenRoom.OpenBorders[(int)ray.Dir][scalar]) { possibleRays.Add(ray); } } if (possibleRays.Count > 0) { LocRay4 locRay = possibleRays[rand.Next(possibleRays.Count)]; raysOut.Remove(locRay); setsTaken++; } else { break; } } if (setsTaken == exitSets.Count) { for (int xx = 0; xx < chosenRoom.Size.X; xx++) { for (int yy = 0; yy < chosenRoom.Size.Y; yy++) { //erase rooms in vicinity Loc loc = new Loc(xx + destRect.Start.X, yy + destRect.Start.Y); //erase halls in vicinity floorPlan.EraseRoom(loc); if (xx > 0) { floorPlan.SetHall(new LocRay4(loc, Dir4.Left), null, new ComponentCollection()); } if (yy > 0) { floorPlan.SetHall(new LocRay4(loc, Dir4.Up), null, new ComponentCollection()); } } } //remove all halls still in the list foreach (LocRay4 rayOut in raysOut) { floorPlan.SetHall(rayOut, null, new ComponentCollection()); } //add room floorPlan.AddRoom(destRect, chosenRoom.Gen, new ComponentCollection()); break; } } } } }
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); }
public void GetWallDir(int gridType, Dir4 result) { // no correct grounds string[] inGrid = { "XXX", "XXX", "XXX", }; switch (gridType) { case 1: // one correct ground, all valid block inGrid = new string[] { "XXX", "XXX", "X.X", }; break; case 2: inGrid = new string[] { "XXX", ".XX", "XXX", }; break; case 3: // multiple correct ground inGrid = new string[] { "XXX", ".XX", "X.X", }; break; case 4: // one correct ground, but one invalid inGrid = new string[] { "XXX", "~XX", "X.X", }; break; case 5: // one correct ground, one crucial diagonal an invalid block inGrid = new string[] { "XX~", "XXX", "X.X", }; break; case 6: // one correct ground, both noncrucial diagonal an invalid block inGrid = new string[] { "XXX", "XXX", "~.~", }; break; default: break; } char[][] map = GridTest.InitGrid(inGrid); bool CheckBlock(Loc testLoc) => map[testLoc.X][testLoc.Y] == 'X'; bool CheckGround(Loc testLoc) => map[testLoc.X][testLoc.Y] == '.'; LocRay4 locRay = Detection.GetWallDir(new Loc(1), CheckBlock, CheckGround); Assert.That(locRay, Is.EqualTo(new LocRay4(new Loc(1), result))); }