/// <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); } } }
/// <summary> /// Generates the position and size of each room and hall, and places it in the specified IFloorPlanGenContext. /// </summary> /// <param name="map"></param> public void PlaceRoomsOnFloor(IFloorPlanGenContext map) { // decide on room sizes for (int ii = 0; ii < this.ArrayRooms.Count; ii++) { this.ChooseRoomBounds(map.Rand, ii); } // decide on halls; write to RoomSideReqs for (int xx = 0; xx < this.VHalls.Length; xx++) { for (int yy = 0; yy < this.VHalls[xx].Length; yy++) { this.ChooseHallBounds(map.Rand, xx, yy, true); } } for (int xx = 0; xx < this.HHalls.Length; xx++) { for (int yy = 0; yy < this.HHalls[xx].Length; yy++) { this.ChooseHallBounds(map.Rand, xx, yy, false); } } GenContextDebug.StepIn("Main Rooms"); List <RoomHallIndex> roomToHall = new List <RoomHallIndex>(); foreach (var plan in this.ArrayRooms) { if (plan.PreferHall) { roomToHall.Add(new RoomHallIndex(map.RoomPlan.HallCount, true)); map.RoomPlan.AddHall((IPermissiveRoomGen)plan.RoomGen, plan.Components); GenContextDebug.DebugProgress("Add Hall Room"); } else { roomToHall.Add(new RoomHallIndex(map.RoomPlan.RoomCount, false)); map.RoomPlan.AddRoom(plan.RoomGen, plan.Components); GenContextDebug.DebugProgress("Added Room"); } } GenContextDebug.StepOut(); GenContextDebug.StepIn("Connecting Halls"); for (int xx = 0; xx < this.VHalls.Length; xx++) { for (int yy = 0; yy < this.VHalls[xx].Length; yy++) { GridHallGroup hallGroup = this.VHalls[xx][yy]; for (int ii = 0; ii < hallGroup.HallParts.Count; ii++) { List <RoomHallIndex> adj = new List <RoomHallIndex>(); if (ii == 0) { int upRoom = this.Rooms[xx][yy]; if (upRoom > -1) { adj.Add(roomToHall[upRoom]); } } else { adj.Add(new RoomHallIndex(map.RoomPlan.HallCount - 1, true)); } if (ii == hallGroup.HallParts.Count - 1) { int downRoom = this.Rooms[xx][yy + 1]; if (downRoom > -1) { adj.Add(roomToHall[downRoom]); } } map.RoomPlan.AddHall(hallGroup.HallParts[ii].RoomGen, hallGroup.HallParts[ii].Components, adj.ToArray()); GenContextDebug.DebugProgress("Add Hall"); } } } for (int xx = 0; xx < this.HHalls.Length; xx++) { for (int yy = 0; yy < this.HHalls[xx].Length; yy++) { GridHallGroup hallGroup = this.HHalls[xx][yy]; for (int ii = 0; ii < hallGroup.HallParts.Count; ii++) { List <RoomHallIndex> adj = new List <RoomHallIndex>(); if (ii == 0) { int leftRoom = this.Rooms[xx][yy]; if (leftRoom > -1) { adj.Add(roomToHall[leftRoom]); } } else { adj.Add(new RoomHallIndex(map.RoomPlan.HallCount - 1, true)); } if (ii == hallGroup.HallParts.Count - 1) { int rightRoom = this.Rooms[xx + 1][yy]; if (rightRoom > -1) { adj.Add(roomToHall[rightRoom]); } } map.RoomPlan.AddHall(hallGroup.HallParts[ii].RoomGen, hallGroup.HallParts[ii].Components, adj.ToArray()); GenContextDebug.DebugProgress("Add Hall"); } } } GenContextDebug.StepOut(); }