public void GetHallTouchRangeLargeRoom(Dir4 dir, int tier, int rangeMin, int rangeMax) { // a room that takes up multiple cells string[] inGrid = { "A.A.0.0", ". . . .", "A.A.0.0", ". . . .", "A.A.0.0", ". . . .", "0.0.0.0", }; TestGridFloorPlan floorPlan = TestGridFloorPlan.InitGridToContext(inGrid, 6, 4); Mock <IRandom> testRand = new Mock <IRandom>(MockBehavior.Strict); IRoomGen testGen = floorPlan.PublicArrayRooms[0].RoomGen; testGen.PrepareSize(testRand.Object, new Loc(5, 10)); testGen.SetLoc(new Loc(1, 2)); IntRange bounds = floorPlan.GetHallTouchRange(testGen, dir, tier); IntRange compareBounds = new IntRange(rangeMin, rangeMax); Assert.That(bounds, Is.EqualTo(compareBounds)); }
public static Rect GetSupportRect(FloorPlan floorPlan, IRoomGen oldGen, IRoomGen newGen, Dir4 dir, List <RoomHallIndex> adjacentsInDir) { bool vertical = dir.ToAxis() == Axis4.Vert; Rect supportRect = newGen.Draw; supportRect.Start += dir.GetLoc() * supportRect.Size.GetScalar(dir.ToAxis()); supportRect.SetScalar(dir, oldGen.Draw.GetScalar(dir)); IntRange minMax = newGen.Draw.GetSide(dir.ToAxis()); foreach (RoomHallIndex adj in adjacentsInDir) { IRoomGen adjGen = floorPlan.GetRoomHall(adj).RoomGen; IntRange adjMinMax = adjGen.Draw.GetSide(dir.ToAxis()); minMax = new IntRange(Math.Min(adjMinMax.Min, minMax.Min), Math.Max(adjMinMax.Max, minMax.Max)); } IntRange oldMinMax = oldGen.Draw.GetSide(dir.ToAxis()); minMax = new IntRange(Math.Max(oldMinMax.Min, minMax.Min), Math.Min(oldMinMax.Max, minMax.Max)); if (vertical) { supportRect.SetScalar(Dir4.Left, minMax.Min); supportRect.SetScalar(Dir4.Right, minMax.Max); } else { supportRect.SetScalar(Dir4.Up, minMax.Min); supportRect.SetScalar(Dir4.Down, minMax.Max); } return(supportRect); }
public void GetSupportRectMultiple() { // the adjacent tile crosses past the border TestFloorPlan floorPlan = TestFloorPlan.InitFloorToContext( new Loc(22, 14), new Rect[] { new Rect(3, 3, 6, 6), new Rect(3, 9, 2, 2), new Rect(7, 9, 2, 2) }, Array.Empty <Rect>(), new Tuple <char, char>[] { Tuple.Create('A', 'B'), Tuple.Create('A', 'C') }); IRoomGen oldGen = floorPlan.GetRoom(0); Mock <IRoomGen> mockTo = new Mock <IRoomGen>(MockBehavior.Strict); mockTo.SetupGet(p => p.Draw).Returns(new Rect(5, 3, 2, 2)); var adjacentsInDir = new List <RoomHallIndex> { new RoomHallIndex(1, false), new RoomHallIndex(2, false), }; Rect rect = AddSpecialRoomTestStep.GetSupportRect(floorPlan, oldGen, mockTo.Object, Dir4.Down, adjacentsInDir); Assert.That(rect, Is.EqualTo(new Rect(3, 5, 6, 4))); }
public void GetSupportRect(int x, int y, Dir4 dir, int expectX, int expectY, int expectW, int expectH) { // the adjacent tile lines up perfectly // 2x2 rooms here TestFloorPlan floorPlan = TestFloorPlan.InitFloorToContext( new Loc(22, 14), new Rect[] { new Rect(3, 3, 6, 6), new Rect(5, 9, 2, 2), new Rect(1, 5, 2, 2), new Rect(5, 1, 2, 2), new Rect(9, 5, 2, 2) }, Array.Empty <Rect>(), new Tuple <char, char>[] { Tuple.Create('A', 'B'), Tuple.Create('A', 'C'), Tuple.Create('A', 'D'), Tuple.Create('A', 'E') }); IRoomGen oldGen = floorPlan.GetRoom(0); Mock <IRoomGen> mockTo = new Mock <IRoomGen>(MockBehavior.Strict); mockTo.SetupGet(p => p.Draw).Returns(new Rect(x, y, 2, 2)); var indexLookup = new Dictionary <Dir4, int> { { Dir4.Down, 1 }, { Dir4.Left, 2 }, { Dir4.Up, 3 }, { Dir4.Right, 4 } }; var adjacentsInDir = new List <RoomHallIndex> { new RoomHallIndex(indexLookup[dir], false) }; Rect rect = AddSpecialRoomTestStep.GetSupportRect(floorPlan, oldGen, mockTo.Object, dir, adjacentsInDir); Assert.That(rect, Is.EqualTo(new Rect(expectX, expectY, expectW, expectH))); }
public void PlaceRoom(IRandom rand, FloorPlan floorPlan, IRoomGen newGen, RoomHallIndex oldRoomHall) { // first get the adjacents of the removed room Dictionary <Dir4, List <RoomHallIndex> > adjacentsByDir = GetDirectionAdjacents(floorPlan, oldRoomHall); IRoomGen oldGen = floorPlan.GetRoomHall(oldRoomHall).RoomGen; // remove the room; update the adjacents too floorPlan.EraseRoomHall(oldRoomHall); foreach (Dir4 dir in DirExt.VALID_DIR4) { for (int jj = 0; jj < adjacentsByDir[dir].Count; jj++) { RoomHallIndex adjRoomHall = adjacentsByDir[dir][jj]; if (adjRoomHall.IsHall == oldRoomHall.IsHall && adjRoomHall.Index > oldRoomHall.Index) { adjacentsByDir[dir][jj] = new RoomHallIndex(adjRoomHall.Index - 1, adjRoomHall.IsHall); } } } var newAdjacents = new List <RoomHallIndex>(); var supportHalls = new Dictionary <Dir4, IPermissiveRoomGen>(); foreach (Dir4 dir in DirExt.VALID_DIR4) { if (newGen.Draw.GetScalar(dir) == oldGen.Draw.GetScalar(dir)) { newAdjacents.AddRange(adjacentsByDir[dir]); } else if (adjacentsByDir[dir].Count > 0) { Rect supportRect = GetSupportRect(floorPlan, oldGen, newGen, dir, adjacentsByDir[dir]); var supportHall = (IPermissiveRoomGen)this.Halls.Pick(rand).Copy(); supportHall.PrepareSize(rand, supportRect.Size); supportHall.SetLoc(supportRect.Start); supportHalls[dir] = supportHall; } } // add the new room var newRoomInd = new RoomHallIndex(floorPlan.RoomCount, false); floorPlan.AddRoom(newGen, true, newAdjacents.ToArray()); // add supporting halls foreach (Dir4 dir in DirExt.VALID_DIR4) { if (supportHalls.ContainsKey(dir)) { // include an attachment to the newly added room List <RoomHallIndex> adjToAdd = new List <RoomHallIndex> { newRoomInd }; adjToAdd.AddRange(adjacentsByDir[dir]); floorPlan.AddHall(supportHalls[dir], adjToAdd.ToArray()); } } }
public virtual int GetSideBorderMatch(IRoomGen newGen, Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, Loc loc, Dir4 dir, int matchValue) { foreach (IRoomGen adj in adjacentsByDir[dir]) { matchValue = Math.Min(matchValue, FloorPlan.GetBorderMatch(adj, newGen, loc, dir.Reverse())); } return(matchValue); }
public virtual bool SpawnInRoom(TGenContext map, RoomHallIndex roomIndex, TSpawnable spawn) { IRoomGen room = map.RoomPlan.GetRoomHall(roomIndex).RoomGen; List <Loc> freeTiles = map.GetFreeTiles(room.Draw); if (freeTiles.Count > 0) { int randIndex = map.Rand.Next(freeTiles.Count); map.PlaceItem(freeTiles[randIndex], spawn); return(true); } return(false); }
protected override List <Loc> getAllFreeTiles(getOpen func) { List <Loc> freeTiles = new List <Loc>(); //get all places that items are eligible for (int ii = 0; ii < RoomPlan.RoomCount; ii++) { IRoomGen room = RoomPlan.GetRoom(ii); List <Loc> tiles = func(room.Draw); freeTiles.AddRange(tiles); } return(freeTiles); }
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 void TransferBorderToAdjacents(RoomHallIndex from) { IFloorRoomPlan basePlan = this.GetRoomHall(from); IRoomGen roomGen = basePlan.RoomGen; List <RoomHallIndex> adjacents = basePlan.Adjacents; foreach (RoomHallIndex adjacent in adjacents) { // first determine if this adjacent should be receiving info if ((!from.IsHall && adjacent.IsHall) || (from.IsHall == adjacent.IsHall && from.Index < adjacent.Index)) { IRoomGen adjacentGen = this.GetRoomHall(adjacent).RoomGen; adjacentGen.ReceiveOpenedBorder(roomGen, GetDirAdjacent(adjacentGen, roomGen)); } } }
/// <summary> /// /// </summary> /// <param name="room"></param> /// <param name="dir">Direction from room to hall.</param> /// <param name="tier"></param> /// <returns></returns> public virtual IntRange GetHallTouchRange(IRoomGen room, Dir4 dir, int tier) { bool vertical = dir.ToAxis() == Axis4.Vert; // The hall will touch the entire side of each room under normal circumstances. // Things get tricky for a target room that occupies more than one cell. // First, try to cover only the part of the target room that's in the cell. // If that's not possible, try to extend the hall until it covers one tile of the target room. IntRange startRange = room.Draw.GetSide(dir.ToAxis()); // factor possibletiles into this calculation int borderLength = room.GetBorderLength(dir); for (int ii = 0; ii < borderLength; ii++) { if (room.GetFulfillableBorder(dir, ii)) { startRange.Min += ii; break; } } for (int ii = 0; ii < borderLength; ii++) { if (room.GetFulfillableBorder(dir, borderLength - 1 - ii)) { startRange.Max -= ii; break; } } int tierStart = vertical ? tier * (this.WidthPerCell + this.CellWall) : tier * (this.HeightPerCell + this.CellWall); int tierLength = vertical ? this.WidthPerCell : this.HeightPerCell; IntRange newRange = new IntRange(Math.Max(startRange.Min, tierStart), Math.Min(startRange.Max, tierStart + tierLength)); if (newRange.Max <= newRange.Min) { // try to extend the hall until it covers one tile of the target room. // first, note that the current end range is covering the zone between the tier and the edge of the room (inverted) // un-invert this and inflate by 1, and you will have a zone that covers 1 tile with the room // get the intersection of this zone and the room. newRange = new IntRange(Math.Max(startRange.Min, newRange.Max - 1), Math.Min(startRange.Max, newRange.Min + 1)); } return(newRange); }
public void DrawOnMap(ITiledGenContext map) { GenContextDebug.StepIn("Main Rooms"); for (int ii = 0; ii < this.Rooms.Count; ii++) { // take in the broad fulfillables from adjacent rooms that have not yet drawn IFloorRoomPlan plan = this.Rooms[ii]; foreach (RoomHallIndex adj in plan.Adjacents) { if (adj.IsHall || adj.Index > ii) { IRoomGen adjacentGen = this.GetRoomHall(adj).RoomGen; plan.RoomGen.ReceiveFulfillableBorder(adjacentGen, GetDirAdjacent(plan.RoomGen, adjacentGen)); } } plan.RoomGen.DrawOnMap(map); this.TransferBorderToAdjacents(new RoomHallIndex(ii, false)); GenContextDebug.DebugProgress("Draw Room"); } GenContextDebug.StepOut(); GenContextDebug.StepIn("Connecting Halls"); for (int ii = 0; ii < this.Halls.Count; ii++) { // take in the broad fulfillables from adjacent rooms that have not yet drawn IFloorRoomPlan plan = this.Halls[ii]; foreach (RoomHallIndex adj in plan.Adjacents) { if (adj.IsHall && adj.Index > ii) { IRoomGen adjacentGen = this.GetRoomHall(adj).RoomGen; plan.RoomGen.ReceiveFulfillableBorder(adjacentGen, GetDirAdjacent(plan.RoomGen, adjacentGen)); } } plan.RoomGen.DrawOnMap(map); this.TransferBorderToAdjacents(new RoomHallIndex(ii, true)); GenContextDebug.DebugProgress("Draw Hall"); } GenContextDebug.StepOut(); }
public override void DistributeSpawns(TGenContext map, List <TSpawnable> spawns) { // gather up all rooms and put in a spawn list // rooms that are farther from the start are more likely to have items var spawningRooms = new SpawnList <RoomHallIndex>(); int[] roomWeights = new int[map.RoomPlan.RoomCount]; // get the start room int startRoom = 0; for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++) { IRoomGen room = map.RoomPlan.GetRoom(ii); if (Collision.InBounds(room.Draw, map.GetLoc(0))) { startRoom = ii; break; } } int maxVal = 1; void NodeAct(int nodeIndex, int distance) { roomWeights[nodeIndex] = distance + 1; maxVal = Math.Max(maxVal, roomWeights[nodeIndex]); } List <int> GetAdjacents(int nodeIndex) => map.RoomPlan.GetAdjacentRooms(nodeIndex); Graph.TraverseBreadthFirst(roomWeights.Length, startRoom, NodeAct, GetAdjacents); int multFactor = int.MaxValue / maxVal / roomWeights.Length; for (int ii = 0; ii < roomWeights.Length; ii++) { spawningRooms.Add(new RoomHallIndex(ii, false), roomWeights[ii] * multFactor); } this.SpawnRandInCandRooms(map, spawningRooms, spawns, this.SuccessPercent); }
protected static bool HasBorderOpening(IRoomGen roomFrom, Rect rectTo, Dir4 expandTo) { Loc diff = roomFrom.Draw.Start - rectTo.Start; // how far ahead the start of source is to dest int offset = diff.GetScalar(expandTo.ToAxis().Orth()); // Traverse the region that both borders touch int sourceLength = roomFrom.GetBorderLength(expandTo); int destLength = rectTo.Size.GetScalar(expandTo.ToAxis().Orth()); for (int ii = Math.Max(0, offset); ii - offset < sourceLength && ii < destLength; ii++) { bool sourceFulfill = roomFrom.GetFulfillableBorder(expandTo, ii - offset); if (sourceFulfill) { return(true); } } return(false); }
public static Dir4 GetDirAdjacent(IRoomGen roomGenFrom, IRoomGen roomGenTo) { Dir4 result = Dir4.None; foreach (Dir4 dir in DirExt.VALID_DIR4) { if (roomGenFrom.Draw.GetScalar(dir) == roomGenTo.Draw.GetScalar(dir.Reverse())) { if (result == Dir4.None) { result = dir; } else { return(Dir4.None); } } } return(result); }
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 void AddRoom(IRoomGen gen, ComponentCollection components, params RoomHallIndex[] attached) { // check against colliding on other rooms (and not halls) foreach (var room in this.Rooms) { if (Collision.Collides(room.RoomGen.Draw, gen.Draw)) { throw new InvalidOperationException("Tried to add on top of an existing room!"); } } foreach (var hall in this.Halls) { if (Collision.Collides(hall.RoomGen.Draw, gen.Draw)) { throw new InvalidOperationException("Tried to add on top of an existing hall!"); } } // check against rooms that go out of bounds if (!this.DrawRect.Contains(gen.Draw)) { throw new InvalidOperationException("Tried to add out of range!"); } // we expect that the room has already been given a size // and that its fulfillables match up with its adjacent's fulfillables. var plan = new FloorRoomPlan(gen, components); // attach everything plan.Adjacents.AddRange(attached); foreach (RoomHallIndex fromRoom in attached) { IFloorRoomPlan fromPlan = this.GetRoomHall(fromRoom); fromPlan.Adjacents.Add(new RoomHallIndex(this.Rooms.Count, false)); } this.Rooms.Add(plan); }
public static int GetBorderMatch(IRoomGen roomFrom, IRoomGen room, Loc candLoc, Dir4 expandTo) { int totalMatch = 0; Loc diff = roomFrom.Draw.Start - candLoc; // how far ahead the start of source is to dest int offset = diff.GetScalar(expandTo.ToAxis().Orth()); // Traverse the region that both borders touch int sourceLength = roomFrom.GetBorderLength(expandTo); int destLength = room.GetBorderLength(expandTo.Reverse()); for (int ii = Math.Max(0, offset); ii - offset < sourceLength && ii < destLength; ii++) { bool sourceFulfill = roomFrom.GetFulfillableBorder(expandTo, ii - offset); bool destFulfill = room.GetFulfillableBorder(expandTo.Reverse(), ii); if (sourceFulfill && destFulfill) { totalMatch++; } } return(totalMatch); }
public void AddRoom(Loc loc, IRoomGen gen, ComponentCollection components, bool preferHall) { this.AddRoom(new Rect(loc, new Loc(1)), gen, components, preferHall); }
public override void Apply(T map) { int chosenAmount = Amount.Pick(map.Rand); if (chosenAmount > 0) { SpawnList <int> spawningRooms = new SpawnList <int>(); //get all places that spawnings are eligible for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++) { IRoomGen room = map.RoomPlan.GetRoom(ii); if (!BaseRoomFilter.PassesAllFilters(map.RoomPlan.GetRoomPlan(ii), this.Filters)) { continue; } spawningRooms.Add(ii, 10000); } int trials = 10 * chosenAmount; for (int ii = 0; ii < trials && chosenAmount > 0; ii++) { if (spawningRooms.SpawnTotal == 0)//check to make sure there's still spawn choices left { break; } int spawnIndex = spawningRooms.PickIndex(map.Rand); int roomNum = spawningRooms.GetSpawn(spawnIndex); Team newTeam = Spawn.GetSpawn(map); if (newTeam == null) { continue; } List <Loc> freeTiles = Grid.FindTilesInBox(map.RoomPlan.GetRoom(roomNum).Draw.Start, map.RoomPlan.GetRoom(roomNum).Draw.Size, (Loc testLoc) => { return(((IGroupPlaceableGenContext <Team>)map).CanPlaceItem(testLoc)); }); //this actually places the members of the team in random scattered locations, leaving them to group together via wandering if (freeTiles.Count >= newTeam.Players.Count) { Loc[] locs = new Loc[newTeam.Players.Count]; for (int jj = 0; jj < newTeam.Players.Count; jj++) { int randIndex = map.Rand.Next(freeTiles.Count); locs[jj] = freeTiles[randIndex]; freeTiles.RemoveAt(randIndex); } ((IGroupPlaceableGenContext <Team>)map).PlaceItems(newTeam, locs); chosenAmount--; } if (freeTiles.Count == 0)//if spawningRooms is now impossible there, remove the room entirely { spawningRooms.RemoveAt(spawnIndex); } else //otherwise decrease spawn rate for room { spawningRooms.SetSpawnRate(spawnIndex, Math.Max(spawningRooms.GetSpawnRate(spawnIndex) * ClumpFactor / 100, 1)); } } } }
public override void ApplyToPath(IRandom rand, FloorPlan floorPlan) { // choose certain rooms in the list to be special rooms // special rooms are required; so make sure they don't overlap IRoomGen newGen = this.Rooms.Pick(rand).Copy(); Loc size = newGen.ProposeSize(rand); newGen.PrepareSize(rand, size); int factor = floorPlan.DrawRect.Area / newGen.Draw.Area; // TODO: accept smaller rooms to replace // bulldozing the surrounding rooms to get the space var room_indices = new SpawnList <RoomHallIndex>(); for (int ii = 0; ii < floorPlan.RoomCount; ii++) { FloorRoomPlan plan = floorPlan.GetRoomPlan(ii); if (!plan.Immutable && plan.RoomGen.Draw.Width >= newGen.Draw.Width && plan.RoomGen.Draw.Height >= newGen.Draw.Height) { room_indices.Add(new RoomHallIndex(ii, false), ComputeRoomChance(factor, plan.RoomGen.Draw, newGen.Draw)); } } for (int ii = 0; ii < floorPlan.HallCount; ii++) { var roomHall = new RoomHallIndex(ii, true); IFloorRoomPlan plan = floorPlan.GetRoomHall(roomHall); if (plan.RoomGen.Draw.Width >= newGen.Draw.Width && plan.RoomGen.Draw.Height >= newGen.Draw.Height) { room_indices.Add(roomHall, ComputeRoomChance(factor, plan.RoomGen.Draw, newGen.Draw)); } } while (room_indices.Count > 0) { int ind = room_indices.PickIndex(rand); RoomHallIndex oldRoomHall = room_indices.GetSpawn(ind); Dictionary <Dir4, List <RoomHallIndex> > adjacentIndicesByDir = GetDirectionAdjacents(floorPlan, oldRoomHall); var adjacentsByDir = new Dictionary <Dir4, List <IRoomGen> >(); foreach (Dir4 dir in DirExt.VALID_DIR4) { adjacentsByDir[dir] = new List <IRoomGen>(); foreach (RoomHallIndex adj in adjacentIndicesByDir[dir]) { adjacentsByDir[dir].Add(floorPlan.GetRoomHall(adj).RoomGen); } } Loc placement = this.FindPlacement(rand, adjacentsByDir, newGen, floorPlan.GetRoomHall(oldRoomHall).RoomGen); if (placement != new Loc(-1)) { newGen.SetLoc(placement); this.PlaceRoom(rand, floorPlan, newGen, oldRoomHall); GenContextDebug.DebugProgress("Set Special Room"); return; } room_indices.RemoveAt(ind); } }
public virtual int GetAllBorderMatch(Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, IRoomGen newGen, IRoomGen oldGen, Loc loc) { // TODO: Currently fails the loc if a single adjacent in a given direction is not met. // Perhaps allow the halls to cover the un-met required adjacent int matchValue = newGen.Draw.Perimeter; if (loc.X == oldGen.Draw.Left) { matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Left, matchValue)); if (matchValue == 0) { return(0); } } if (loc.X == oldGen.Draw.Right - newGen.Draw.Width) { matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Right, matchValue)); if (matchValue == 0) { return(0); } } if (loc.Y == oldGen.Draw.Top) { matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Up, matchValue)); if (matchValue == 0) { return(0); } } if (loc.Y == oldGen.Draw.Bottom - newGen.Draw.Height) { matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Down, matchValue)); if (matchValue == 0) { return(0); } } return(matchValue); }
public override void ApplyToPath(IRandom rand, FloorPlan floorPlan) { for (int ii = 0; ii < 10; ii++) { // always clear before trying floorPlan.Clear(); int tilesToOpen = floorPlan.DrawRect.Area * this.FillPercent.Pick(rand) / 100; if (tilesToOpen < 1) { tilesToOpen = 1; } int addBranch = this.BranchRatio.Pick(rand); int tilesLeft = tilesToOpen; // choose a room IRoomGen room = this.PrepareRoom(rand, floorPlan, false); // place in a random location room.SetLoc(new Loc( rand.Next(floorPlan.DrawRect.Left, floorPlan.DrawRect.Right - room.Draw.Width + 1), rand.Next(floorPlan.DrawRect.Top, floorPlan.DrawRect.Bottom - room.Draw.Height + 1))); floorPlan.AddRoom(room, this.RoomComponents.Clone()); GenContextDebug.DebugProgress("Start Room"); tilesLeft -= room.Draw.Area; // repeat this process until the requisite room amount is met int pendingBranch = 0; while (tilesLeft > 0) { (int area, int rooms)terminalResult = this.ExpandPath(rand, floorPlan, false); (int area, int rooms)branchResult = (0, 0); if (terminalResult.area > 0) { tilesLeft -= terminalResult.area; // add branch PER ROOM when we add over the min threshold for (int jj = 0; jj < terminalResult.rooms; jj++) { if (floorPlan.RoomCount + floorPlan.HallCount - terminalResult.rooms + jj + 1 > 2) { pendingBranch += addBranch; } } } else if (this.NoForcedBranches) { break; } else { pendingBranch = 100; } while (pendingBranch >= 100 && tilesLeft > 0) { branchResult = this.ExpandPath(rand, floorPlan, true); if (branchResult.area == 0) { break; } pendingBranch -= 100; // if we add any more than one room, that also counts as a branchable node pendingBranch += (branchResult.rooms - 1) * addBranch; tilesLeft -= branchResult.area; } if (terminalResult.area == 0 && branchResult.area == 0) { break; } } if (tilesLeft <= 0) { break; } } }
public Loc FindPlacement(IRandom rand, Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, IRoomGen newGen, IRoomGen oldGen) { SpawnList <Loc> possiblePlacements = this.GetPossiblePlacements(adjacentsByDir, newGen, oldGen); return(possiblePlacements.SpawnTotal == 0 ? new Loc(-1) : possiblePlacements.Pick(rand)); }
public SpawnList <Loc> GetPossiblePlacements(Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, IRoomGen newGen, IRoomGen oldGen) { // test all positions around perimeter Rect oldRect = oldGen.Draw; SpawnList <Loc> possiblePlacements = new SpawnList <Loc>(); // top and bottom for (int xx = oldRect.Left; xx < oldRect.Right - newGen.Draw.Width + 1; xx++) { Loc topLoc = new Loc(xx, oldRect.Top); int topMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, topLoc); if (topMatch > 0) { possiblePlacements.Add(topLoc, topMatch); } Loc bottomLoc = new Loc(xx, oldRect.Bottom - newGen.Draw.Height); if (bottomLoc != topLoc) { int bottomMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, bottomLoc); if (bottomMatch > 0) { possiblePlacements.Add(bottomLoc, bottomMatch); } } } // left and right for (int yy = oldRect.Top + 1; yy < oldRect.Bottom - newGen.Draw.Height; yy++) { Loc leftLoc = new Loc(oldRect.Left, yy); int leftMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, leftLoc); if (leftMatch > 0) { possiblePlacements.Add(leftLoc, leftMatch); } Loc rightLoc = new Loc(oldRect.Right - newGen.Draw.Width, yy); if (rightLoc != leftLoc) { int rightMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, rightLoc); if (rightMatch > 0) { possiblePlacements.Add(rightLoc, rightMatch); } } } if (possiblePlacements.SpawnTotal == 0) { if (oldRect.Width >= newGen.Draw.Width + 2 && oldRect.Height >= newGen.Draw.Height + 2) { for (int xx = oldRect.Left + 1; xx < oldRect.Right - newGen.Draw.Width; xx++) { for (int yy = oldRect.Top + 1; yy < oldRect.Bottom - newGen.Draw.Height; yy++) { possiblePlacements.Add(new Loc(xx, yy), 1); } } } } return(possiblePlacements); }
public ListPathBranchExpansion(RoomHallIndex from, IRoomGen room, IPermissiveRoomGen hall) { this.From = from; this.Room = room; this.Hall = hall; }
public static void AddLegalPlacements(SpawnList <Loc> possiblePlacements, FloorPlan floorPlan, RoomHallIndex indexFrom, IRoomGen roomFrom, IRoomGen room, Dir4 expandTo) { bool vertical = expandTo.ToAxis() == Axis4.Vert; // this scaling factor equalizes the chances of long sides vs short sides int reverseSideMult = vertical ? roomFrom.Draw.Width * room.Draw.Width : roomFrom.Draw.Height * room.Draw.Height; IntRange side = roomFrom.Draw.GetSide(expandTo.ToAxis()); // subtract the room's original size, not the inflated trialrect size side.Min -= (vertical ? room.Draw.Size.X : room.Draw.Size.Y) - 1; Rect tryRect = room.Draw; // expand in every direction // this will create a one-tile buffer to check for collisions tryRect.Inflate(1, 1); int currentScalar = side.Min; while (currentScalar < side.Max) { // compute the location Loc trialLoc = roomFrom.GetEdgeRectLoc(expandTo, room.Draw.Size, currentScalar); tryRect.Start = trialLoc + new Loc(-1, -1); // check for collisions (not counting the rectangle from) List <RoomHallIndex> collisions = floorPlan.CheckCollision(tryRect); // find the first tile in which no collisions will be found int maxCollideScalar = currentScalar; bool collided = false; foreach (RoomHallIndex collision in collisions) { if (collision != indexFrom) { IRoomGen collideRoom = floorPlan.GetRoomHall(collision).RoomGen; // this is the point at which the new room will barely touch the collided room // the +1 at the end will move it into the safe zone maxCollideScalar = Math.Max(maxCollideScalar, vertical ? collideRoom.Draw.Right : collideRoom.Draw.Bottom); collided = true; } } // if no collisions were hit, do final checks and add the room if (!collided) { Loc locTo = roomFrom.GetEdgeRectLoc(expandTo, room.Draw.Size, currentScalar); // must be within the borders of the floor! if (floorPlan.DrawRect.Contains(new Rect(locTo, room.Draw.Size))) { // check the border match and if add to possible placements int chanceTo = FloorPlan.GetBorderMatch(roomFrom, room, locTo, expandTo); if (chanceTo > 0) { possiblePlacements.Add(locTo, chanceTo * reverseSideMult); } } } currentScalar = maxCollideScalar + 1; } }
/// <summary> /// Gets the minimum range along the side of a room that includes all of its fulfillable borders. /// Special cases arise if the room is multi-cell. /// </summary> /// <param name="room"></param> /// <param name="dir">Direction from room to hall.</param> /// <param name="tier"></param> /// <returns></returns> public virtual IntRange GetHallTouchRange(IRoomGen room, Dir4 dir, int tier) { bool vertical = dir.ToAxis() == Axis4.Vert; // The hall will touch the whole fulfillable side of each room under normal circumstances. // Things get tricky for a target room that occupies more than one cell. // First, try to cover only the part of the target room that's in the cell. int tierStart = vertical ? tier * (this.WidthPerCell + this.CellWall) : tier * (this.HeightPerCell + this.CellWall); int tierLength = vertical ? this.WidthPerCell : this.HeightPerCell; IntRange tierRange = new IntRange(tierStart, tierStart + tierLength); IntRange roomRange = room.Draw.GetSide(dir.ToAxis()); // factor possibletiles into this calculation int borderStart = tierStart - roomRange.Min; if (borderStart < 0) { tierRange.Min -= borderStart; borderStart = 0; } for (int ii = borderStart; ii < roomRange.Length; ii++) { if (room.GetFulfillableBorder(dir, ii)) { break; } else { tierRange.Min += 1; } } int borderEnd = tierStart + tierLength - roomRange.Min; if (borderEnd > roomRange.Length) { tierRange.Max += roomRange.Length - borderEnd; borderEnd = roomRange.Length; } for (int ii = borderEnd - 1; ii >= 0; ii--) { if (room.GetFulfillableBorder(dir, ii)) { break; } else { tierRange.Max -= 1; } } if (tierRange.Max > tierRange.Min) { return(tierRange); } // If that's not possible, then it means that the room must have fulfillable tiles outside of the current bound. // Try to extend the hall until it covers one fulfillable tile of the target room. // Easy method: note that the current tierRange range is covering the zone between the tier and the edge of the room (inverted) // There will be either a workable range at the start or a workable range at the end, never neither. IntRange startRange = new IntRange(tierRange.Max - 1, tierStart + 1); IntRange endRange = new IntRange(tierStart + tierLength - 1, tierRange.Min + 1); bool chooseStart = true; bool chooseEnd = true; // if tierRanges reached the absolute limits of the roomRange, then there is no fulfillable tile on that side if (startRange.Min < roomRange.Min) { chooseStart = false; } else if (endRange.Length > startRange.Length) { chooseEnd = false; } if (endRange.Max > roomRange.Max) { chooseEnd = false; } else if (startRange.Length > endRange.Length) { chooseStart = false; } if (!chooseStart && !chooseEnd) { throw new ArgumentException("PrepareFulfillableBorders did not open at least one open tile for each direction!"); } if (chooseStart) { return(startRange); } return(endRange); }
public void AddRoom(Loc loc, IRoomGen gen, ComponentCollection components) { this.AddRoom(new Rect(loc, new Loc(1)), gen, components, false); }
public void AddRoom(Rect rect, IRoomGen gen, ComponentCollection components) { this.AddRoom(rect, gen, components, false); }