public void EraseRoom(Loc loc) { int roomIndex = this.Rooms[loc.X][loc.Y]; GridRoomPlan room = this.ArrayRooms[roomIndex]; this.ArrayRooms.RemoveAt(roomIndex); for (int xx = room.Bounds.Start.X; xx < room.Bounds.End.X; xx++) { for (int yy = room.Bounds.Start.Y; yy < room.Bounds.End.Y; yy++) { this.Rooms[xx][yy] = -1; } } for (int xx = 0; xx < this.GridWidth; xx++) { for (int yy = 0; yy < this.GridHeight; yy++) { if (this.Rooms[xx][yy] > roomIndex) { this.Rooms[xx][yy]--; } } } }
private static Loc GetBoundsSize(GridPlan floorPlan, GridRoomPlan plan) { Loc cellSize = new Loc(plan.Bounds.Width * floorPlan.WidthPerCell, plan.Bounds.Height * floorPlan.HeightPerCell); Loc cellWallSize = new Loc((plan.Bounds.Width - 1) * floorPlan.CellWall, (plan.Bounds.Height - 1) * floorPlan.CellWall); return(cellSize + cellWallSize); }
public override void ApplyToPath(IRandom rand, GridPlan floorPlan) { // choose certain rooms in the list to be special rooms // special rooms are required; so make sure they don't overlap List <int> room_indices = new List <int>(); for (int ii = 0; ii < floorPlan.RoomCount; ii++) { GridRoomPlan plan = floorPlan.GetRoomPlan(ii); if (!plan.Immutable && !plan.CountsAsHall()) { room_indices.Add(ii); } } if (room_indices.Count > 0) { int ind = rand.Next(room_indices.Count); GridRoomPlan plan = floorPlan.GetRoomPlan(room_indices[ind]); plan.RoomGen = this.Rooms.Pick(rand).Copy(); plan.Immutable = true; room_indices.RemoveAt(ind); GenContextDebug.DebugProgress("Set Special Room"); } }
public override void ApplyToPath(IRandom rand, GridPlan floorPlan) { List <int> candidates = new List <int>(); for (int ii = 0; ii < floorPlan.RoomCount; ii++) { if (!floorPlan.GetRoomPlan(ii).Immutable) { List <int> adjacents = floorPlan.GetAdjacentRooms(ii); if (adjacents.Count > 1) { candidates.Add(ii); } } } // our candidates are all rooms except immutables and terminals int amountToDefault = this.DefaultRatio.Pick(rand) * candidates.Count / 100; for (int ii = 0; ii < amountToDefault; ii++) { int randIndex = rand.Next(candidates.Count); GridRoomPlan plan = floorPlan.GetRoomPlan(candidates[randIndex]); plan.RoomGen = new RoomGenDefault <T>(); plan.PreferHall = true; candidates.RemoveAt(randIndex); GenContextDebug.DebugProgress("Defaulted Room"); } }
/// <summary> /// Decides on the room bounds for each room. /// </summary> /// <param name="rand"></param> /// <param name="roomIndex"></param> public void ChooseRoomBounds(IRandom rand, int roomIndex) { GridRoomPlan roomPair = this.ArrayRooms[roomIndex]; // the RoomGens are allowed to choose any size period, but this function will cap them at the cell sizes Loc size = roomPair.RoomGen.ProposeSize(rand); Rect cellBounds = this.GetCellBounds(roomPair.Bounds); size = new Loc(Math.Min(size.X, cellBounds.Width), Math.Min(size.Y, cellBounds.Height)); roomPair.RoomGen.PrepareSize(rand, size); Loc start = cellBounds.Start + new Loc(rand.Next(cellBounds.Size.X - size.X + 1), rand.Next(cellBounds.Size.Y - size.Y + 1)); roomPair.RoomGen.SetLoc(start); }
public void AddRoom(Rect rect, IRoomGen gen, ComponentCollection components, bool preferHall) { Rect floorRect = new Rect(0, 0, this.GridWidth, this.GridHeight); if (!floorRect.Contains(rect)) { throw new ArgumentOutOfRangeException(nameof(rect), "Cannot add room out of bounds!"); } for (int xx = rect.Start.X; xx < rect.End.X; xx++) { for (int yy = rect.Start.Y; yy < rect.End.Y; yy++) { if (this.Rooms[xx][yy] != -1) { throw new InvalidOperationException("Tried to add on top of an existing room!"); } if (xx > rect.Start.X && this.HHalls[xx - 1][yy].MainHall != null) { throw new InvalidOperationException("Tried to add on top of an existing hall!"); } if (yy > rect.Start.Y && this.VHalls[xx][yy - 1].MainHall != null) { throw new InvalidOperationException("Tried to add on top of an existing hall!"); } } } if (preferHall && !(gen is IPermissiveRoomGen)) { throw new InvalidOperationException("Cannot prefer hall for a non-permissive gen!"); } var room = new GridRoomPlan(rect, gen.Copy(), components) { PreferHall = preferHall, }; this.ArrayRooms.Add(room); for (int xx = rect.Start.X; xx < rect.End.X; xx++) { for (int yy = rect.Start.Y; yy < rect.End.Y; yy++) { this.Rooms[xx][yy] = this.ArrayRooms.Count - 1; } } }
public List <int> GetAdjacentRooms(int roomIndex) { List <int> returnList = new List <int>(); GridRoomPlan room = this.ArrayRooms[roomIndex]; for (int ii = 0; ii < room.Bounds.Size.X; ii++) { // above int up = this.GetRoomNum(new LocRay4(room.Bounds.X + ii, room.Bounds.Y, Dir4.Up)); if (up > -1 && !returnList.Contains(up)) { returnList.Add(up); } // below int down = this.GetRoomNum(new LocRay4(room.Bounds.X + ii, room.Bounds.End.Y - 1, Dir4.Down)); if (down > -1 && !returnList.Contains(down)) { returnList.Add(down); } } for (int ii = 0; ii < room.Bounds.Size.Y; ii++) { // left int left = this.GetRoomNum(new LocRay4(room.Bounds.X, room.Bounds.Y + ii, Dir4.Left)); if (left > -1 && !returnList.Contains(left)) { returnList.Add(left); } // right int right = this.GetRoomNum(new LocRay4(room.Bounds.End.X - 1, room.Bounds.Y + ii, Dir4.Right)); if (right > -1 && !returnList.Contains(right)) { returnList.Add(right); } } return(returnList); }
public override void ApplyToPath(IRandom rand, GridPlan floorPlan) { IRoomGen newGen = this.Rooms.Pick(rand).Copy(); Loc size = newGen.ProposeSize(rand); // choose certain rooms in the list to be special rooms // special rooms are required; so make sure they don't overlap List <int> room_indices = new List <int>(); for (int ii = 0; ii < floorPlan.RoomCount; ii++) { GridRoomPlan plan = floorPlan.GetRoomPlan(ii); if (!BaseRoomFilter.PassesAllFilters(plan, this.Filters)) { continue; } if (plan.PreferHall) { continue; } Loc boundsSize = GetBoundsSize(floorPlan, plan); if (boundsSize.X >= size.X && boundsSize.Y >= size.Y) { room_indices.Add(ii); } } if (room_indices.Count > 0) { int ind = rand.Next(room_indices.Count); GridRoomPlan plan = floorPlan.GetRoomPlan(room_indices[ind]); plan.RoomGen = newGen; foreach (RoomComponent component in this.RoomComponents) { plan.Components.Set(component.Clone()); } room_indices.RemoveAt(ind); GenContextDebug.DebugProgress("Set Special Room"); } }
public override void ApplyToPath(IRandom rand, GridPlan floorPlan) { if (floorPlan.GridWidth < 3 || floorPlan.GridHeight < 3) { throw new InvalidOperationException("Not enough room to create path."); } int maxRooms = (2 * floorPlan.GridWidth) + (2 * floorPlan.GridHeight) - 4; int roomOpen = maxRooms * this.CircleRoomRatio.Pick(rand) / 100; int paths = this.Paths.Pick(rand); if (roomOpen < 1 && paths < 1) { roomOpen = 1; } GenContextDebug.StepIn("Outer Circle"); // draw the top and bottom for (int xx = 0; xx < floorPlan.GridWidth; xx++) { this.RollOpenRoom(rand, floorPlan, new Loc(xx, 0), ref roomOpen, ref maxRooms); GenContextDebug.DebugProgress("Room"); this.RollOpenRoom(rand, floorPlan, new Loc(xx, floorPlan.GridHeight - 1), ref roomOpen, ref maxRooms); GenContextDebug.DebugProgress("Room"); if (xx > 0) { floorPlan.SetHall(new LocRay4(new Loc(xx, 0), Dir4.Left), this.GenericHalls.Pick(rand), this.HallComponents.Clone()); GenContextDebug.DebugProgress("Hall"); floorPlan.SetHall(new LocRay4(new Loc(xx, floorPlan.GridHeight - 1), Dir4.Left), this.GenericHalls.Pick(rand), this.HallComponents.Clone()); GenContextDebug.DebugProgress("Hall"); } } // draw the left and right (excluding the top and bottom) for (int yy = 0; yy < floorPlan.GridHeight; yy++) { // exclude the top and bottom if (yy > 0 && yy < floorPlan.GridHeight - 1) { this.RollOpenRoom(rand, floorPlan, new Loc(0, yy), ref roomOpen, ref maxRooms); GenContextDebug.DebugProgress("Room"); this.RollOpenRoom(rand, floorPlan, new Loc(floorPlan.GridWidth - 1, yy), ref roomOpen, ref maxRooms); GenContextDebug.DebugProgress("Room"); } if (yy > 0) { floorPlan.SetHall(new LocRay4(new Loc(0, yy), Dir4.Up), this.GenericHalls.Pick(rand), this.HallComponents.Clone()); GenContextDebug.DebugProgress("Hall"); floorPlan.SetHall(new LocRay4(new Loc(floorPlan.GridWidth - 1, yy), Dir4.Up), this.GenericHalls.Pick(rand), this.HallComponents.Clone()); GenContextDebug.DebugProgress("Hall"); } } GenContextDebug.StepOut(); GenContextDebug.StepIn("Inner Paths"); Rect innerRect = new Rect(1, 1, floorPlan.GridWidth - 2, floorPlan.GridHeight - 2); // create inner paths for (int pathsMade = 0; pathsMade < paths; pathsMade++) { GenContextDebug.StepIn($"Path {pathsMade}"); Dir4 startDir = DirExt.VALID_DIR4.ElementAt(rand.Next(DirExt.DIR4_COUNT)); int x = rand.Next(innerRect.Start.X, innerRect.End.X); int y = rand.Next(innerRect.Start.Y, innerRect.End.Y); switch (startDir) { case Dir4.Down: y = 0; break; case Dir4.Left: x = floorPlan.GridWidth - 1; break; case Dir4.Up: y = floorPlan.GridHeight - 1; break; case Dir4.Right: x = 0; break; case Dir4.None: break; default: throw new ArgumentOutOfRangeException(nameof(startDir), "Invalid enum value."); } Loc wanderer = new Loc(x, y); Dir4 prevDir = Dir4.None; // direction of movement int pathLength = (startDir.ToAxis() == Axis4.Vert) ? innerRect.Height : innerRect.Width; for (int currentLength = 0; currentLength < pathLength; currentLength++) { Dir4 chosenDir = startDir; // avoid this block the first time if (currentLength > 0) { List <Dir4> dirs = new List <Dir4>(); foreach (Dir4 dir in DirExt.VALID_DIR4) { // do not backtrack if (dir == prevDir) { continue; } // do not hit edge if (!Collision.InBounds(innerRect, wanderer + dir.GetLoc())) { continue; } dirs.Add(dir); } chosenDir = dirs[rand.Next(dirs.Count)]; } Loc dest = wanderer + chosenDir.GetLoc(); GridRoomPlan existingRoom = floorPlan.GetRoomPlan(dest); if (existingRoom == null) { if (currentLength == pathLength - 1) // only the end room can be a non-hall { floorPlan.AddRoom(dest, this.GenericRooms.Pick(rand), this.RoomComponents.Clone()); } else { floorPlan.AddRoom(dest, this.GetDefaultGen(), this.HallComponents.Clone(), true); } GenContextDebug.DebugProgress("Room"); } else if (existingRoom.PreferHall) { if (currentLength == pathLength - 1) { // override the hall room existingRoom.RoomGen = this.GenericRooms.Pick(rand).Copy(); existingRoom.PreferHall = false; } } floorPlan.SetHall(new LocRay4(wanderer, chosenDir), this.GenericHalls.Pick(rand), this.HallComponents.Clone()); GenContextDebug.DebugProgress("Hall"); wanderer = dest; prevDir = chosenDir.Reverse(); } GenContextDebug.StepOut(); } GenContextDebug.StepOut(); }
/// <summary> /// Decides on the bounds for each hall. Also writes to the adjacent rooms' SideReqs and tile permissions /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="vertical"></param> /// <param name="rand">todo: describe rand parameter on ChooseHallBounds</param> public void ChooseHallBounds(IRandom rand, int x, int y, bool vertical) { GridRoomPlan startRoom = this.GetRoomPlan(new Loc(x, y)); GridRoomPlan endRoom = this.GetRoomPlan(new Loc(x + (vertical ? 0 : 1), y + (vertical ? 1 : 0))); GridHallGroup hallGroup = vertical ? this.VHalls[x][y] : this.HHalls[x][y]; if (hallGroup.MainHall != null) { // also sets the sidereqs int tier = vertical ? x : y; Dir4 dir = vertical ? Dir4.Down : Dir4.Right; IntRange startRange = this.GetHallTouchRange(startRoom.RoomGen, dir, tier); IntRange endRange = this.GetHallTouchRange(endRoom.RoomGen, dir.Reverse(), tier); IntRange combinedRange = new IntRange(Math.Min(startRange.Min, endRange.Min), Math.Max(startRange.Max, endRange.Max)); Loc start = startRoom.RoomGen.Draw.End; Loc end = endRoom.RoomGen.Draw.Start; Rect startCell = this.GetCellBounds(startRoom.Bounds); Rect endCell = this.GetCellBounds(endRoom.Bounds); Rect bounds = vertical ? new Rect(combinedRange.Min, start.Y, combinedRange.Length, end.Y - start.Y) : new Rect(start.X, combinedRange.Min, end.X - start.X, combinedRange.Length); // a side constitutes intruding bound when the rectangle moves forward enough to go to the other side // and the other side touched is outside of side B's bound (including borders) // startRange intrudes if startRange goes outside end's tier (borders included) bool startIntrude = !endCell.GetSide(dir.ToAxis()).Contains(startRange); // and end is greater than the edge (borders excluded) bool endTouch = bounds.GetScalar(dir) == endCell.GetScalar(dir.Reverse()); bool endIntrude = !startCell.GetSide(dir.ToAxis()).Contains(endRange); // and end is greater than the edge (borders excluded) bool startTouch = bounds.GetScalar(dir.Reverse()) == startCell.GetScalar(dir); // neither side intrudes bound: use the computed rectangle if ((!startIntrude && !endIntrude) || (endTouch && startTouch) || (!(startIntrude && endIntrude) && ((startIntrude && endTouch) || (endIntrude && startTouch)))) { hallGroup.MainHall.RoomGen.PrepareSize(rand, bounds.Size); hallGroup.MainHall.RoomGen.SetLoc(bounds.Start); } else { int divPoint = startCell.GetScalar(dir) + 1; IntRange startDivRange = startRange; IntRange endDivRange = endRange; if (startIntrude && !endIntrude) { // side A intrudes bound, side B does not: divide A and B; doesn't matter who gets border // side A touches border, side B does not: divide A and B; A gets border // // side A does not, side B touches border: A gets border; don't need B - this cannot happen // side A touches border, side B touches border: A gets border; don't need B - this cannot happen // // in short, divide with start getting the border // startDivRange needs to contain endRange startDivRange = combinedRange; } else if (!startIntrude && endIntrude) { // side A does not, side B intrudes bound: divide A and B; doesn't matter who gets border // side A does not, side B touches border: divide A and B; B gets border // // side A touches border, side B does not: B gets border; don't need A - this cannot happen // side A touches border, side B touches border: B gets border; don't need B - this cannot happen // // in short, divide with end getting the border // endDivRange needs to contain startRange divPoint = startCell.GetScalar(dir); endDivRange = combinedRange; } else { // side A intrudes bound, side B intrudes bound: divide A and B; doesn't matter who gets border if (startTouch) { // side A touches border, side B does not: divide A and B; A gets border } if (endTouch) { // side A does not, side B touches border: divide A and B; B gets border divPoint = startCell.GetScalar(dir); } // side A touches border, side B touches border: A gets border; don't need B - this cannot happen // both sides need to cover the intersection of their cells IntRange interCellSide = IntRange.Intersect(startCell.GetSide(dir.ToAxis()), endCell.GetSide(dir.ToAxis())); startDivRange = IntRange.IncludeRange(startDivRange, interCellSide); endDivRange = IntRange.IncludeRange(endDivRange, interCellSide); } Rect startBox = vertical ? new Rect(startDivRange.Min, start.Y, startDivRange.Length, divPoint - start.Y) : new Rect(start.X, startDivRange.Min, divPoint - start.X, startDivRange.Length); Rect endBox = vertical ? new Rect(endDivRange.Min, divPoint, endDivRange.Length, end.Y - divPoint) : new Rect(divPoint, endDivRange.Min, end.X - divPoint, endDivRange.Length); GridHallPlan originalHall = hallGroup.MainHall; hallGroup.HallParts.Add(new GridHallPlan((IPermissiveRoomGen)originalHall.RoomGen.Copy(), originalHall.Components)); hallGroup.HallParts[0].RoomGen.PrepareSize(rand, startBox.Size); hallGroup.HallParts[0].RoomGen.SetLoc(startBox.Start); hallGroup.HallParts[1].RoomGen.PrepareSize(rand, endBox.Size); hallGroup.HallParts[1].RoomGen.SetLoc(endBox.Start); } } }
public override void ApplyToPath(IRandom rand, GridPlan floorPlan) { List <LocRay4> endBranches = new List <LocRay4>(); for (int ii = 0; ii < floorPlan.RoomCount; ii++) { GridRoomPlan roomPlan = floorPlan.GetRoomPlan(ii); if (!BaseRoomFilter.PassesAllFilters(roomPlan, this.Filters)) { continue; } if (roomPlan.Bounds.Size == new Loc(1)) { List <int> adjacents = floorPlan.GetAdjacentRooms(ii); if (adjacents.Count == 1) { endBranches.Add(new LocRay4(roomPlan.Bounds.Start)); } } } List <List <LocRay4> > candBranchPoints = new List <List <LocRay4> >(); for (int nn = 0; nn < endBranches.Count; nn++) { LocRay4 chosenBranch = endBranches[nn]; while (chosenBranch.Loc != new Loc(-1)) { List <LocRay4> connectors = new List <LocRay4>(); List <LocRay4> candBonds = new List <LocRay4>(); foreach (Dir4 dir in DirExt.VALID_DIR4) { if (dir != chosenBranch.Dir) { if (floorPlan.GetHall(new LocRay4(chosenBranch.Loc, dir)) != null) { connectors.Add(new LocRay4(chosenBranch.Loc, dir)); } else { Loc loc = chosenBranch.Loc + dir.GetLoc(); if (Collision.InBounds(floorPlan.GridWidth, floorPlan.GridHeight, loc) && floorPlan.GetRoomIndex(loc) > -1) { candBonds.Add(new LocRay4(chosenBranch.Loc, dir)); } } } } if (connectors.Count == 1) { if (candBonds.Count > 0) { candBranchPoints.Add(candBonds); chosenBranch = new LocRay4(new Loc(-1)); } else { chosenBranch = new LocRay4(connectors[0].Traverse(1), connectors[0].Dir.Reverse()); } } else { chosenBranch = new LocRay4(new Loc(-1)); } } } // compute a goal amount of terminals to connect // this computation ignores the fact that some terminals may be impossible var randBin = new RandBinomial(candBranchPoints.Count, this.ConnectPercent); int connectionsLeft = randBin.Pick(rand); while (candBranchPoints.Count > 0 && connectionsLeft > 0) { // choose random point to connect int randIndex = rand.Next(candBranchPoints.Count); List <LocRay4> candBonds = candBranchPoints[randIndex]; LocRay4 chosenDir = candBonds[rand.Next(candBonds.Count)]; // connect floorPlan.SetHall(chosenDir, this.GenericHalls.Pick(rand), this.HallComponents); candBranchPoints.RemoveAt(randIndex); GenContextDebug.DebugProgress("Connected Branch"); connectionsLeft--; // check to see if connection destination was also a candidate, // counting this as a double if so for (int ii = candBranchPoints.Count - 1; ii >= 0; ii--) { if (candBranchPoints[ii][0].Loc == chosenDir.Traverse(1)) { candBranchPoints.RemoveAt(ii); connectionsLeft--; } } } }