/// <summary> /// Choose a random point on the outside edge of this rectangle /// </summary> /// <param name="edge"></param> /// <param name="rng"></param> /// <param name="endOffset"></param> /// <param name="i"></param> /// <param name="j"></param> public void RandomPointOnEdge(CompassDirection edge, Random rng, int endOffset, ref int i, ref int j) { if (edge == CompassDirection.North) { j = YMax + 1; } else if (edge == CompassDirection.East) { i = XMax + 1; } else if (edge == CompassDirection.South) { j = YMin - 1; } else if (edge == CompassDirection.West) { i = XMin - 1; } if (edge.IsHorizontal()) { j = rng.Next(YMin, YMax - endOffset + 1); } else { i = rng.Next(XMin, XMax - endOffset + 1); } }
public bool GrowRoom(int iDoor, int jDoor, RoomTemplate template, CompassDirection direction, bool createDoor, Room parent) { bool result = false; int doorSize = template.EntryWidth; var bounds = new IntRectangle(iDoor, jDoor); // Current room bounds bool iFrozen = false; // Is growth in the x-direction frozen? bool jFrozen = false; // Is growth in the y-direction frozen? //Generate target dimensions: var dimensions = new IntInterval( template.Dimension1.Random(_RNG), template.Dimension2.Random(_RNG)); //Create starting tiles in front of doorway: bounds.Move(direction, 1); if (direction == CompassDirection.North || direction == CompassDirection.South) { bounds.Grow(CompassDirection.East, doorSize - 1); } else { bounds.Grow(CompassDirection.North, doorSize - 1); } if (CheckAvailability(bounds)) { // Grow outwards, checking availability: CompassDirection growDirection = direction; int persistance = 5; //Failures before abort while (persistance > 0) { if (!(iFrozen && growDirection.IsHorizontal()) && !(jFrozen && growDirection.IsVertical())) { if (CheckAvailability(bounds.GrowZone(growDirection, 1))) { bounds.Grow(growDirection, 1); } else { persistance--; } } if (bounds.XSize + 1 >= dimensions.Max) { iFrozen = true; } if (bounds.XSize + 1 > dimensions.Min && bounds.YSize + 1 == dimensions.Min) { jFrozen = true; } if (bounds.YSize + 1 >= dimensions.Max) { jFrozen = true; } if (bounds.YSize + 1 > dimensions.Min && bounds.XSize + 1 == dimensions.Min) { iFrozen = true; } if (jFrozen && iFrozen) { persistance = 0; } else { growDirection = ExitDirection(template.ExitPlacement, direction); //TODO: ExitPlacement from RoomTemplate? } } if (template.RoomType == RoomType.Circulation && (!PreventParallelCorridors || IsParallelToCorridor(bounds))) { return(false); //Abort parallel corridors } if ((bounds.XSize + 1 >= template.Dimension1.Min && bounds.YSize + 1 >= template.Dimension2.Min || (bounds.XSize + 1 >= template.Dimension2.Min && bounds.YSize + 1 >= template.Dimension1.Min))) { // Reached target size - create room // Create doorway: if (createDoor) { GenerateDoorway(iDoor, jDoor, direction, doorSize); } // Create room: Room newRoom = GenerateRoom(bounds, template); //Take snapshot: TakeSnapshot(); if (template.RoomType == RoomType.Exit) { ExitPlaced = true; } //TODO: Store room & connections if (template.RoomType != RoomType.Circulation) { result = true; //Circulation rooms cannot validate chains } //Sprout new rooms: int tries = template.SproutTries; CompassDirection doorDirection = direction; int iNewDoor = 0; int jNewDoor = 0; bool symmetryLock = true; while (tries > 0 && (template.MaxConnections < 0 || newRoom.Connections.Count < template.MaxConnections)) { RoomTemplate nextRoom = NextRoom(template); if (nextRoom != null) { int newDoorWidth = nextRoom.EntryWidth; if (!symmetryLock && _RNG.NextDouble() < template.SymmetryChance) { symmetryLock = true; //Create door opposite last doorDirection = doorDirection.Reverse(); } else { symmetryLock = false; //Select random growth direction: doorDirection = ExitDirection(template.ExitPlacement, direction); } //Select door position for this try: bounds.RandomPointOnEdge(doorDirection, _RNG, newDoorWidth - 1, ref iNewDoor, ref jNewDoor); if (RecursiveGrowth(iNewDoor, jNewDoor, nextRoom, doorDirection, true, newRoom)) { result = true; } } tries -= 1; } if (result == false) { DeleteRoom(newRoom); } } } else { if (createDoor && AreAllType(bounds, CellGenerationType.Void) && AvailableForDoorway(iDoor, jDoor, direction, template.EntryWidth)) { // TODO: Check room connections GenerateDoorway(iDoor, jDoor, direction, template.EntryWidth); } } return(result); }