/// <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> /// 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); } }
/// <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; } }