public override void DistributeSpawns(TGenContext map, List <TSpawnable> spawns) { // random per room, not per-tile var spawningRooms = new SpawnList <RoomHallIndex>(); var terminalRooms = new SpawnList <RoomHallIndex>(); // TODO: higher likelihoods for terminals at the ends of longer paths for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++) { spawningRooms.Add(new RoomHallIndex(ii, false)); List <int> adjacent = map.RoomPlan.GetAdjacentRooms(ii); if (adjacent.Count == 1) { terminalRooms.Add(new RoomHallIndex(ii, false)); } } if (this.IncludeHalls) { for (int ii = 0; ii < map.RoomPlan.HallCount; ii++) { spawningRooms.Add(new RoomHallIndex(ii, true)); List <RoomHallIndex> adjacent = map.RoomPlan.GetRoomHall(new RoomHallIndex(ii, true)).Adjacents; if (adjacent.Count == 1) { terminalRooms.Add(new RoomHallIndex(ii, true)); } } } // first attempt to spawn in the terminals; remove from terminal list if successful this.SpawnRandInCandRooms(map, terminalRooms, spawns, 0); this.SpawnRandInCandRooms(map, spawningRooms, spawns, 100); }
public override void DistributeSpawns(TGenContext map, List <TSpawnable> spawns) { // random per room, not per-tile var spawningRooms = new SpawnList <RoomHallIndex>(); for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++) { if (!BaseRoomFilter.PassesAllFilters(map.RoomPlan.GetRoomPlan(ii), this.Filters)) { continue; } spawningRooms.Add(new RoomHallIndex(ii, false), 10); } if (this.IncludeHalls) { for (int ii = 0; ii < map.RoomPlan.HallCount; ii++) { if (!BaseRoomFilter.PassesAllFilters(map.RoomPlan.GetHallPlan(ii), this.Filters)) { continue; } spawningRooms.Add(new RoomHallIndex(ii, true), 10); } } this.SpawnRandInCandRooms(map, spawningRooms, spawns, 100); }
public virtual void SpawnRandInCandRooms(TGenContext map, SpawnList <RoomHallIndex> spawningRooms, List <TSpawnable> spawns, int successPercent) { while (spawningRooms.Count > 0 && spawns.Count > 0) { int randIndex = spawningRooms.PickIndex(map.Rand); RoomHallIndex roomIndex = spawningRooms.GetSpawn(randIndex); // try to spawn the item if (this.SpawnInRoom(map, roomIndex, spawns[spawns.Count - 1])) { GenContextDebug.DebugProgress("Placed Object"); // remove the item spawn spawns.RemoveAt(spawns.Count - 1); if (successPercent <= 0) { spawningRooms.RemoveAt(randIndex); } else { int newRate = Math.Max(1, spawningRooms.GetSpawnRate(randIndex) * successPercent / 100); spawningRooms.SetSpawnRate(randIndex, newRate); } } else { spawningRooms.RemoveAt(randIndex); } } }
protected SpawnList(SpawnList <T> other) { this.spawns = new List <SpawnRate>(other.spawns); foreach (SpawnRate item in other.spawns) { this.spawns.Add(new SpawnRate(item.Spawn, item.Rate)); } }
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>(); Dictionary <RoomHallIndex, int> roomWeights = new Dictionary <RoomHallIndex, int>(); // get the start room int startRoom = 0; for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++) { FloorRoomPlan room = map.RoomPlan.GetRoomPlan(ii); if (Collision.InBounds(room.RoomGen.Draw, map.GetLoc(0))) { startRoom = ii; break; } } int maxVal = 1; void NodeAct(RoomHallIndex nodeIndex, int distance) { roomWeights[nodeIndex] = distance + 1; maxVal = Math.Max(maxVal, roomWeights[nodeIndex]); } Graph.TraverseBreadthFirst(new RoomHallIndex(startRoom, false), NodeAct, map.RoomPlan.GetAdjacents); int multFactor = int.MaxValue / maxVal / roomWeights.Count; foreach (RoomHallIndex idx in roomWeights.Keys) { IFloorRoomPlan room = map.RoomPlan.GetRoomHall(idx); if (idx.IsHall && !this.IncludeHalls) { continue; } if (!BaseRoomFilter.PassesAllFilters(room, this.Filters)) { continue; } if (roomWeights[idx] == 0) { continue; } spawningRooms.Add(idx, roomWeights[idx] * multFactor); } this.SpawnRandInCandRooms(map, spawningRooms, spawns, this.SuccessPercent); }
protected static ListPathTraversalNode?ChooseConnection(IRandom rand, FloorPlan floorPlan, List <RoomHallIndex> candList) { SpawnList <ListPathTraversalNode> expansions = GetPossibleExpansions(floorPlan, candList); if (expansions.Count > 0) { return(expansions.Pick(rand)); } else { return(null); } }
public CategorySpawnChooser(CategorySpawnChooser <T> other) { Spawns = new SpawnDict <string, SpawnList <T> >(); foreach (string key in other.Spawns.GetKeys()) { SpawnList <T> list = new SpawnList <T>(); SpawnList <T> otherList = other.Spawns.GetSpawn(key); for (int ii = 0; ii < otherList.Count; ii++) { list.Add(otherList.GetSpawn(ii), otherList.GetSpawnRate(ii)); } Spawns.Add(key, list, other.Spawns.GetSpawnRate(key)); } }
protected static SpawnList <ListPathTraversalNode> GetPossibleExpansions(FloorPlan floorPlan, List <RoomHallIndex> candList) { // get all probabilities. // the probability of an extension is the distance that the target room is from the start room, in rooms var expansions = new SpawnList <ListPathTraversalNode>(); for (int nn = 0; nn < candList.Count; nn++) { // find the room to connect to // go through all sides of all rooms (randomly) RoomHallIndex chosenFrom = candList[nn]; IFloorRoomPlan planFrom = floorPlan.GetRoomHall(chosenFrom); // exhausting all possible directions (randomly) foreach (Dir4 dir in DirExt.VALID_DIR4) { bool forbidExtend = false; foreach (RoomHallIndex adjacent in planFrom.Adjacents) { Rect adjRect = floorPlan.GetRoomHall(adjacent).RoomGen.Draw; if (planFrom.RoomGen.Draw.GetScalar(dir) == adjRect.GetScalar(dir.Reverse())) { forbidExtend = true; break; } } if (!forbidExtend) { // find a rectangle to connect it with ListPathTraversalNode?expandToResult = GetRoomToConnect(floorPlan, chosenFrom, dir); if (expandToResult is ListPathTraversalNode expandTo) { int prb = floorPlan.GetDistance(expandTo.From, expandTo.To); if (prb < 0) { expansions.Add(expandTo, 1); } else if (prb > 0) { expansions.Add(expandTo, prb); } } } } } return(expansions); }
public SpawnList <T> GetSpawnList(int level) { SpawnList <T> newList = new SpawnList <T>(); foreach (SpawnRange spawn in this.spawns) { if (spawn.Range.Min <= level && level < spawn.Range.Max) { newList.Add(spawn.Spawn, spawn.Rate); } } return(newList); }
public T Pick(IRandom rand) { SpawnDict <string, SpawnList <T> > tempSpawn = new SpawnDict <string, SpawnList <T> >(); foreach (string key in Spawns.GetKeys()) { SpawnList <T> otherList = Spawns.GetSpawn(key); if (!otherList.CanPick) { continue; } tempSpawn.Add(key, otherList, Spawns.GetSpawnRate(key)); } SpawnList <T> choice = tempSpawn.Pick(rand); return(choice.Pick(rand)); }
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); }
public override void DistributeSpawns(TGenContext map, List <TSpawnable> spawns) { // random per room, not per-tile var spawningRooms = new SpawnList <RoomHallIndex>(); for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++) { spawningRooms.Add(new RoomHallIndex(ii, false)); } if (this.IncludeHalls) { for (int ii = 0; ii < map.RoomPlan.HallCount; ii++) { spawningRooms.Add(new RoomHallIndex(ii, true)); } } this.SpawnRandInCandRooms(map, spawningRooms, spawns, 100); }
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 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 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 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> /// Chooses a node to expand the path from based on the specified branch setting. /// </summary> /// <param name="availableExpansions">todo: describe availableExpansions parameter on ChooseRoomExpansion</param> /// <param name="prepareRoom">todo: describe prepareRoom parameter on ChooseRoomExpansion</param> /// <param name="hallPercent">todo: describe hallPercent parameter on ChooseRoomExpansion</param> /// <param name="rand"></param> /// <param name="floorPlan"></param> /// <returns>A set of instructions on how to expand the path.</returns> public static ListPathBranchExpansion?ChooseRoomExpansion(RoomPrep prepareRoom, int hallPercent, IRandom rand, FloorPlan floorPlan, List <RoomHallIndex> availableExpansions) { if (availableExpansions.Count == 0) { return(null); } for (int ii = 0; ii < 30; ii++) { // choose the next room to add to RoomHallIndex firstExpandFrom = availableExpansions[rand.Next(availableExpansions.Count)]; RoomHallIndex expandFrom = firstExpandFrom; IRoomGen roomFrom = floorPlan.GetRoomHall(firstExpandFrom).RoomGen; // choose the next room to add // choose room size/fulfillables // note: by allowing halls to be picked as extensions, we run the risk of adding dead-end halls // halls should always terminate at rooms? // this means... doubling up with hall+room? bool addHall = rand.Next(100) < hallPercent; IRoomGen hall = null; if (addHall) { hall = prepareRoom(rand, floorPlan, true); // randomly choose a perimeter to assign this to SpawnList <Loc> possibleHallPlacements = new SpawnList <Loc>(); foreach (Dir4 dir in DirExt.VALID_DIR4) { AddLegalPlacements(possibleHallPlacements, floorPlan, expandFrom, roomFrom, hall, dir); } // at this point, all possible factors for whether a placement is legal or not is accounted for // therefor just pick one if (possibleHallPlacements.Count == 0) { continue; } // randomly choose one Loc hallCandLoc = possibleHallPlacements.Pick(rand); // set location hall.SetLoc(hallCandLoc); // change the roomfrom for the upcoming room expandFrom = new RoomHallIndex(-1, false); roomFrom = hall; } IRoomGen room = prepareRoom(rand, floorPlan, false); // randomly choose a perimeter to assign this to SpawnList <Loc> possiblePlacements = new SpawnList <Loc>(); foreach (Dir4 dir in DirExt.VALID_DIR4) { AddLegalPlacements(possiblePlacements, floorPlan, expandFrom, roomFrom, room, dir); } // at this point, all possible factors for whether a placement is legal or not is accounted for // therefore just pick one if (possiblePlacements.Count > 0) { // randomly choose one Loc candLoc = possiblePlacements.Pick(rand); // set location room.SetLoc(candLoc); return(new ListPathBranchExpansion(firstExpandFrom, room, (IPermissiveRoomGen)hall)); } } return(null); }