public void AddingOverlappingTemplatesWorksIfOverlapIsTransparent() { //Load sample template 8x4 Assembly _assembly = Assembly.GetExecutingAssembly(); Stream roomFileStream = _assembly.GetManifestResourceStream("DDRogueTest.testdata.vaults.testsolid1.room"); RoomTemplate room1 = RoomTemplateLoader.LoadTemplateFromFile(roomFileStream, StandardTemplateMapping.terrainMapping); RoomTemplate corridor1 = LoadTemplateFromFileRogueBasin("RogueBasin.bin.Debug.vaults.corridortemplate3x1.room"); TemplatedMapBuilder mapGen = new TemplatedMapBuilder(); //Start TemplatePositioned templatePos1 = new TemplatePositioned(0, 0, 0, room1, 0); mapGen.AddPositionedTemplate(templatePos1); //End TemplatePositioned templatePos2 = new TemplatePositioned(-10, 20, 0, room1, 0); mapGen.AddPositionedTemplate(templatePos2); //Middle TemplatePositioned templatePos3 = new TemplatePositioned(-8, 30, 0, room1, 0); mapGen.AddPositionedTemplate(templatePos3); //Corridor from start - end that overlaps middle var expandedCorridorAndPoint = RoomTemplateUtilities.ExpandCorridorTemplateLShaped(6, 28, true, corridor1); var positionedCorridor = new TemplatePositioned(-2, 4, 0, expandedCorridorAndPoint.Item1, 3); Assert.IsTrue(mapGen.AddPositionedTemplate(positionedCorridor)); }
private static void AddStandardDecorativeFeaturesToRoom(int level, TemplatePositioned positionedRoom, int featuresToPlace, DecorationFeatureDetails.Decoration decorationDetails) { var bridgeRouter = new RoomFilling(positionedRoom.Room); var floorPoints = RoomTemplateUtilities.GetPointsInRoomWithTerrain(positionedRoom.Room, RoomTemplateTerrain.Floor); for (int i = 0; i < featuresToPlace; i++) { var randomPoint = floorPoints.RandomElement(); floorPoints.Remove(randomPoint); if (bridgeRouter.SetSquareUnWalkableIfMaintainsConnectivity(randomPoint)) { var featureLocationInMapCoords = positionedRoom.Location + randomPoint; Game.Dungeon.AddFeatureBlocking(new Features.StandardDecorativeFeature(decorationDetails.representation, decorationDetails.colour), level, featureLocationInMapCoords, true); LogFile.Log.LogEntryDebug("Placing feature in room " + positionedRoom.RoomIndex + " at location " + featureLocationInMapCoords, LogDebugLevel.Medium); } if (floorPoints.Count() == 0) { break; } } }
private void AddCorridorsBetweenOpenDoors(TemplatedMapGenerator templatedGenerator, int totalExtraConnections) { var extraConnections = 0; var allDoors = templatedGenerator.PotentialDoors; //Find all possible doors matches that aren't in the same room var allBendDoorPossibilities = from d1 in allDoors from d2 in allDoors where RoomTemplateUtilities.CanBeConnectedWithBendCorridor(d1.MapCoords, d1.DoorLocation, d2.MapCoords, d2.DoorLocation) && d1.OwnerRoomIndex != d2.OwnerRoomIndex select new { origin = d1, target = d2 }; var allLDoorPossibilities = from d1 in allDoors from d2 in allDoors where RoomTemplateUtilities.CanBeConnectedWithLShapedCorridor(d1.MapCoords, d1.DoorLocation, d2.MapCoords, d2.DoorLocation) && d1.OwnerRoomIndex != d2.OwnerRoomIndex select new { origin = d1, target = d2 }; var allOverlappingDoorPossibilities = from d1 in allDoors from d2 in allDoors where d1.MapCoords == d2.MapCoords && d1.OwnerRoomIndex != d2.OwnerRoomIndex select new { origin = d1, target = d2 }; //Materialize for speed var allMatchingDoorPossibilities = allBendDoorPossibilities.Union(allLDoorPossibilities).Union(allOverlappingDoorPossibilities).ToList(); //var allMatchingDoorPossibilities = allLDoorPossibilities; //var allMatchingDoorPossibilities = allBendDoorPossibilities; var shuffleMatchingDoors = allMatchingDoorPossibilities.Shuffle(Game.Random); for (int i = 0; i < allMatchingDoorPossibilities.Count; i++) { //Try a random combination to see if it works var doorsToTry = shuffleMatchingDoors.ElementAt(i); LogFile.Log.LogEntryDebug("Trying door " + doorsToTry.origin.MapCoords + " to " + doorsToTry.target.MapCoords, LogDebugLevel.Medium); bool success = templatedGenerator.JoinDoorsWithCorridor(doorsToTry.origin, doorsToTry.target, RandomCorridor()); if (success) { extraConnections++; } if (extraConnections > totalExtraConnections) { break; } } //Previous code (was super-slow!) //while (allMatchingDoorPossibilities.Any() && extraConnections < totalExtraConnections) //In any case, remove this attempt //var doorsToTry = allMatchingDoorPossibilities.ElementAt(Game.Random.Next(allMatchingDoorPossibilities.Count())); //allMatchingDoorPossibilities = allMatchingDoorPossibilities.Except(Enumerable.Repeat(doorsToTry, 1)); //order n - making it slow? }
private void AddNewDoorsToPotentialDoors(TemplatePositioned positionedRoom, int roomIndex) { //Store a reference to each potential door in the room int noDoors = positionedRoom.PotentialDoors.Count(); //var currentDoorLocations = potentialDoors.Select(d => d.MapCoords); for (int i = 0; i < noDoors; i++) { //if (!currentDoorLocations.Contains(positionedRoom.PotentialDoors[i])) potentialDoors.Add(new DoorInfo(positionedRoom, roomIndex, i, RoomTemplateUtilities.GetDoorLocation(positionedRoom.Room, i))); } }
/// <summary> /// Replace a room template with a smaller one. Aligns new template with old door. /// This should only be called on dead-ends /// Enforces that replacement rooms can only override floor areas of old rooms (helping to avoid some breakage) /// </summary> public bool ReplaceRoomTemplate(int roomToReplaceIndex, Connection existingRoomConnection, RoomTemplate replacementRoom, int replaceRoomDoorIndex) { var templateToReplace = templates[roomToReplaceIndex]; if (templateToReplace.PotentialDoors.Count() > 1) { throw new ApplicationException("Can't replace rooms with >1 doors"); } var doorToConnection = GetDoorForConnection(existingRoomConnection); Tuple <TemplatePositioned, Point> replacementRoomTuple = RoomTemplateUtilities.AlignRoomOverlapping(replacementRoom, roomToReplaceIndex, templateToReplace, replaceRoomDoorIndex, doorToConnection.DoorIndexInRoom); var replacementRoomTemplate = replacementRoomTuple.Item1; //Check if the overlapping room can be placed if (!mapBuilder.CanBePlacedOverlappingOtherTemplates(replacementRoomTemplate)) { return(false); } //Blank the old room area var voidedOldRoomTemplate = RoomTemplateUtilities.TransparentTemplate(templateToReplace); mapBuilder.UnconditionallyOverridePositionedTemplate(voidedOldRoomTemplate); //Override with new template mapBuilder.OverridePositionedTemplate(replacementRoomTemplate); //Ensure that the room is replaced in the index templates[roomToReplaceIndex] = replacementRoomTemplate; //We don't change the connectivity or doors return(true); }
/// <summary> /// Place a room template aligned with an existing door. /// Returns Connection(Source = existing room or corridor to new room, Target = new room)) /// </summary> public Connection PlaceRoomTemplateAlignedWithExistingDoor(RoomTemplate roomTemplateToPlace, RoomTemplate corridorTemplate, DoorInfo existingDoor, int newRoomDoorIndex, int distanceApart) { var newRoomIndex = NextRoomIndex(); Point existingDoorLoc = existingDoor.MapCoords; Tuple <TemplatePositioned, Point> newRoomTuple = RoomTemplateUtilities.AlignRoomFacing(roomTemplateToPlace, newRoomIndex, existingDoor.OwnerRoom, newRoomDoorIndex, existingDoor.DoorIndexInRoom, distanceApart); var alignedNewRoom = newRoomTuple.Item1; var alignedDoorLocation = newRoomTuple.Item2; var alignedDoorIndex = alignedNewRoom.PotentialDoors.IndexOf(alignedDoorLocation); var alignedDoor = new DoorInfo(alignedNewRoom, newRoomIndex, alignedDoorIndex, RoomTemplateUtilities.GetDoorLocation(alignedNewRoom.Room, alignedDoorIndex)); //In order to place this successfully, we need to be able to both place the room and a connecting corridor if (!mapBuilder.CanBePlacedWithoutOverlappingOtherTemplates(alignedNewRoom)) { throw new ApplicationException("Room failed to place because overlaps existing room"); } //Increase next room for any corridor we may add IncreaseNextRoomIndex(); TemplatePositioned corridorTemplateConnectingRooms = null; Connection connectionToNewRoom = null; if (distanceApart > 1) { //Need points that are '1-in' from the doors var doorOrientation = RoomTemplateUtilities.GetDoorLocation(existingDoor.OwnerRoom.Room, existingDoor.DoorIndexInRoom); bool isHorizontal = doorOrientation == RoomTemplate.DoorLocation.Left || doorOrientation == RoomTemplate.DoorLocation.Right; var corridorTermini = RoomTemplateUtilities.CorridorTerminalPointsBetweenDoors(existingDoorLoc, existingDoor.DoorLocation, alignedDoorLocation, RoomTemplateUtilities.GetOppositeDoorLocation(existingDoor.DoorLocation)); var corridorIndex = NextRoomIndex(); if (corridorTermini.Item1 == corridorTermini.Item2) { corridorTemplateConnectingRooms = RoomTemplateUtilities.GetTemplateForSingleSpaceCorridor(corridorTermini.Item1, RoomTemplateUtilities.ArePointsOnVerticalLine(corridorTermini.Item1, corridorTermini.Item2), 0, corridorTemplate, corridorIndex); } else { corridorTemplateConnectingRooms = RoomTemplateUtilities.GetTemplateForCorridorBetweenPoints(corridorTermini.Item1, corridorTermini.Item2, 0, corridorTemplate, corridorIndex); } //Implicit guarantee that the corridor won't overlap with the new room we're about to place //(but it may overlap other previously placed rooms or corridors) if (!mapBuilder.CanBePlacedWithoutOverlappingOtherTemplates(corridorTemplateConnectingRooms)) { throw new ApplicationException("Room failed to place because corridor overlaps existing room"); } //Place the corridor mapBuilder.AddPositionedTemplate(corridorTemplateConnectingRooms); templates[corridorIndex] = corridorTemplateConnectingRooms; IncreaseNextRoomIndex(); //Add connections to the old and new rooms connectionToNewRoom = new Connection(corridorIndex, newRoomIndex); connectivityMap.AddRoomConnection(existingDoor.OwnerRoomIndex, corridorIndex); LogFile.Log.LogEntryDebug("Adding connection: " + existingDoor.OwnerRoomIndex + " to " + corridorIndex, LogDebugLevel.Medium); connectivityMap.AddRoomConnection(corridorIndex, newRoomIndex); LogFile.Log.LogEntryDebug("Adding connection: " + corridorIndex + " to " + newRoomIndex, LogDebugLevel.Medium); connectionDoors.Add(new Connection(existingDoor.OwnerRoomIndex, corridorIndex).Ordered, existingDoor); connectionDoors.Add(connectionToNewRoom.Ordered, alignedDoor); } else { //No corridor - a direct connection between the rooms connectionToNewRoom = new Connection(existingDoor.OwnerRoomIndex, newRoomIndex); connectivityMap.AddRoomConnection(existingDoor.OwnerRoomIndex, newRoomIndex); connectionDoors.Add(connectionToNewRoom.Ordered, alignedDoor); LogFile.Log.LogEntryDebug("Adding connection: " + existingDoor.OwnerRoomIndex + " to " + newRoomIndex, LogDebugLevel.Medium); } //Place the room bool successfulPlacement = mapBuilder.AddPositionedTemplate(alignedNewRoom); if (!successfulPlacement) { LogFile.Log.LogEntryDebug("Room failed to place because overlaps own corridor - bug", LogDebugLevel.High); throw new ApplicationException("Room failed to place because overlaps own corridor - bug"); } templates[newRoomIndex] = alignedNewRoom; //Add the new potential doors (excluding the one we are linked on) //Can't find a nice linq alternative int noDoors = alignedNewRoom.PotentialDoors.Count(); for (int i = 0; i < noDoors; i++) { if (alignedNewRoom.PotentialDoors[i] == alignedDoorLocation) { continue; } potentialDoors.Add(new DoorInfo(alignedNewRoom, newRoomIndex, i, RoomTemplateUtilities.GetDoorLocation(alignedNewRoom.Room, i))); } //If successful, remove the candidate door from the list potentialDoors.Remove(existingDoor); return(connectionToNewRoom); }
/// <summary> /// Join 2 doors with a corridor. They must be on the opposite sides of their parent rooms (for now) /// </summary> public bool JoinDoorsWithCorridor(DoorInfo firstDoor, DoorInfo secondDoor, RoomTemplate corridorTemplate) { try { if (connectionDoors.ContainsKey(new Connection(firstDoor.OwnerRoomIndex, secondDoor.OwnerRoomIndex).Ordered)) { LogFile.Log.LogEntryDebug("No allowing 2nd connection between rooms for now - revisit past 7DRL", LogDebugLevel.High); return(false); } var firstDoorLoc = RoomTemplateUtilities.GetDoorLocation(firstDoor.OwnerRoom.Room, firstDoor.DoorIndexInRoom); var secondDoorLoc = RoomTemplateUtilities.GetDoorLocation(secondDoor.OwnerRoom.Room, secondDoor.DoorIndexInRoom); var firstDoorCoord = firstDoor.MapCoords; var secondDoorCoord = secondDoor.MapCoords; var corridorTermini = RoomTemplateUtilities.CorridorTerminalPointsBetweenDoors(firstDoor.MapCoords, firstDoor.DoorLocation, secondDoor.MapCoords, secondDoor.DoorLocation); bool canDoLSharedCorridor = RoomTemplateUtilities.CanBeConnectedWithLShapedCorridor(firstDoorCoord, firstDoorLoc, secondDoorCoord, secondDoorLoc); bool canDoBendCorridor = RoomTemplateUtilities.CanBeConnectedWithBendCorridor(firstDoorCoord, firstDoorLoc, secondDoorCoord, secondDoorLoc); bool canDoStraightCorridor = RoomTemplateUtilities.CanBeConnectedWithStraightCorridor(firstDoorCoord, firstDoorLoc, secondDoorCoord, secondDoorLoc); bool areAdjacent = corridorTermini.Item1 == secondDoorCoord && corridorTermini.Item2 == firstDoorCoord; bool areOverlapping = firstDoorCoord == secondDoorCoord; if (!canDoLSharedCorridor && !canDoBendCorridor && !canDoStraightCorridor && !areAdjacent && !areOverlapping) { throw new ApplicationException("No corridor available to connect this type of door"); } if (areAdjacent || areOverlapping) { //Add a direct connection in the connectivity graph connectivityMap.AddRoomConnection(firstDoor.OwnerRoomIndex, secondDoor.OwnerRoomIndex); connectionDoors.Add(new Connection(firstDoor.OwnerRoomIndex, secondDoor.OwnerRoomIndex).Ordered, firstDoor); } else { //Create template var horizontal = false; if (firstDoorLoc == RoomTemplate.DoorLocation.Left || firstDoorLoc == RoomTemplate.DoorLocation.Right) { horizontal = true; } int xOffset = corridorTermini.Item2.x - corridorTermini.Item1.x; int yOffset = corridorTermini.Item2.y - corridorTermini.Item1.y; RoomTemplate expandedCorridor; Point corridorTerminus1InTemplate; if (canDoBendCorridor) { int transition = (int)Math.Floor(yOffset / 2.0); if (horizontal == true) { transition = (int)Math.Floor(xOffset / 2.0); } var expandedCorridorAndPoint = RoomTemplateUtilities.ExpandCorridorTemplateBend(xOffset, yOffset, transition, horizontal, corridorTemplate); expandedCorridor = expandedCorridorAndPoint.Item1; corridorTerminus1InTemplate = expandedCorridorAndPoint.Item2; } else if (canDoLSharedCorridor) { var expandedCorridorAndPoint = RoomTemplateUtilities.ExpandCorridorTemplateLShaped(xOffset, yOffset, horizontal, corridorTemplate); expandedCorridor = expandedCorridorAndPoint.Item1; corridorTerminus1InTemplate = expandedCorridorAndPoint.Item2; } else { var offsetToUse = horizontal ? xOffset : yOffset; var expandedCorridorAndPoint = RoomTemplateUtilities.ExpandCorridorTemplateStraight(offsetToUse, horizontal, corridorTemplate); expandedCorridor = expandedCorridorAndPoint.Item1; corridorTerminus1InTemplate = expandedCorridorAndPoint.Item2; } //Place corridor //Match corridor tile to location of door Point topLeftCorridor = corridorTermini.Item1 - corridorTerminus1InTemplate; var corridorRoomIndex = NextRoomIndex(); var positionedCorridor = new TemplatePositioned(topLeftCorridor.x, topLeftCorridor.y, 0, expandedCorridor, corridorRoomIndex); if (!mapBuilder.CanBePlacedWithoutOverlappingOtherTemplates(positionedCorridor)) { return(false); } //Place the corridor mapBuilder.AddPositionedTemplate(positionedCorridor); templates[corridorRoomIndex] = positionedCorridor; IncreaseNextRoomIndex(); //Add connections to the old and new rooms connectivityMap.AddRoomConnection(firstDoor.OwnerRoomIndex, corridorRoomIndex); connectivityMap.AddRoomConnection(corridorRoomIndex, secondDoor.OwnerRoomIndex); connectionDoors.Add(new Connection(firstDoor.OwnerRoomIndex, corridorRoomIndex).Ordered, firstDoor); connectionDoors.Add(new Connection(corridorRoomIndex, secondDoor.OwnerRoomIndex).Ordered, secondDoor); } //Remove both doors from the potential list potentialDoors.Remove(firstDoor); potentialDoors.Remove(secondDoor); return(true); } catch (ApplicationException ex) { LogFile.Log.LogEntryDebug("Failed to join doors: " + ex.Message, LogDebugLevel.Medium); return(false); } }
public IEnumerable <Point> GetBoundaryPointsInRoomOfTerrain(int roomIndex) { var roomRelativePoints = RoomTemplateUtilities.GetBoundaryFloorPointsInRoom(rooms[roomIndex].Room); return(roomRelativePoints.Select(p => new Point(rooms[roomIndex].Location + p))); }
public IEnumerable <Point> GetAllPointsInRoomOfTerrain(int roomIndex, RoomTemplateTerrain terrainToFind) { var roomRelativePoints = RoomTemplateUtilities.GetPointsInRoomWithTerrain(rooms[roomIndex].Room, terrainToFind); return(roomRelativePoints.Select(p => new Point(rooms[roomIndex].Location + p))); }
/// <summary> /// Returns point in map coords of this level in the required room of terrain /// </summary> /// <param name="roomIndex"></param> /// <param name="terrainToFind"></param> /// <returns></returns> public Point GetRandomPointInRoomOfTerrain(int roomIndex, RoomTemplateTerrain terrainToFind) { var roomRelativePoint = RoomTemplateUtilities.GetRandomPointWithTerrain(rooms[roomIndex].Room, terrainToFind); return(new Point(rooms[roomIndex].Location + roomRelativePoint)); }