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