/// <summary> /// True = valid placement found, room has been updated to the correct offset. /// False = no valid connections, room has been updated to last tried offset (but is probably useless). /// </summary> /// <param name="room"></param> /// <param name="door"></param> /// <param name="directions"></param> /// <returns></returns> private static bool CheckRoomAgainstGrid( Room room, FloorTile door, Directions[] directions ) { // kind of cumbersome, but allows random selection and deletion by reference. // Arrays are more difficult to remove things from. List<Directions> dirs = new List<Directions>(); for( int i=0; i<directions.Length; i++ ) dirs.Add(directions[i]); // try attaching to the north int w = room.cells.GetLength(0); int h = room.cells.GetLength(1); Directions d; // Pick a direction specified, and test it. // Avoids obvious bias against North, and allows specific tests for certain room types (halls, for example) while( dirs.Count > 0 ) { d = dirs[rand.Next(dirs.Count)]; dirs.Remove(d); switch( d ) { case Directions.North: // try attaching to the north room.SetRoomPosition(door.x - w/2, door.y-h+1); if( CheckRoomTilesAgainstGrid(room, door) ) return true; break; case Directions.South: // try attaching to the south room.SetRoomPosition(door.x - w/2, door.y); if( CheckRoomTilesAgainstGrid(room, door) ) return true; break; case Directions.East: // try attaching to the east room.SetRoomPosition(door.x-w+1, door.y-h/2); if( CheckRoomTilesAgainstGrid(room, door) ) return true; break; case Directions.West: // try attaching to the west room.SetRoomPosition(door.x, door.y-h/2); if( CheckRoomTilesAgainstGrid(room, door) ) return true; break; } } // no valid connection found. return false; }
/// <summary> /// Tries to place the specified room. /// True = successful, and the connecting door has been flagged. /// False = unable to find a connection. /// </summary> /// <param name="rooms"></param> /// <param name="room"></param> /// <param name="roomType"></param> /// <param name="allowConnectionBias"></param> /// <param name="targetDoor"></param> /// <returns></returns> private static bool PlaceRoom(List<Room> rooms, Room room, CastleRoomType roomType, bool allowConnectionBias, FloorTile targetDoor ) { int w = room.cells.GetLength(0); int h = room.cells.GetLength(1); if( rooms.Count == 0 ) { // place in middle room.SetRoomPosition(grid.GetLength(0)/2 - w/2, grid.GetLength(1)/2 - h/2); } else { // pick a door to attach to, build from there. List<FloorTile> doors = new List<FloorTile>(); FloorTile connectionDoor = null; if( targetDoor != null ) { doors.Add(targetDoor); } else if( allowConnectionBias ) { switch( roomType ) { case CastleRoomType.LongHall: // custom bias to connect long Halls to Great Rooms if at all possible. foreach( Room r in rooms ) if( r.type == CastleRoomType.GreatroomCircle ||r.type == CastleRoomType.GreatRoomSquare ||r.type == CastleRoomType.GreatRoomRectangle ) foreach( FloorTile door in r.doors ) if( door.type == FloorType.DoorClosed) doors.Add(door); break; case CastleRoomType.GreatroomCircle: case CastleRoomType.GreatRoomRectangle: case CastleRoomType.GreatRoomSquare: // Greatrooms should try to attach to the end of hallways. // Since the LongHall are generated with the end doors first, we can // reference those tow doors directly without searching though the room's doors list foreach( Room r in rooms ) if( r.type == CastleRoomType.LongHall ) { if( r.doors[0].type == FloorType.DoorClosed) doors.Add(r.doors[0]); if( r.doors[1].type == FloorType.DoorClosed) doors.Add(r.doors[1]); } break; default: // no custom doors list - the default of "All of them" will be used below break; } } // Check for custom doors list - if there are none, default to use all doors in all rooms for tries. if( doors.Count == 0 ) { foreach( Room r in rooms ) foreach( FloorTile door in r.doors ) if( door.type == FloorType.DoorClosed) doors.Add(door); } // In the event of a LongHall, we'd like to attach it so that it // traveles away from the room being attached to, rather than attaching along the side of the hall. Directions[] directions; if( roomType == CastleRoomType.LongHall ) { if( w>h ) { // E/W hall - try to attach on East or West side only directions = new Directions[] { Directions.East, Directions.West }; } else { // N/S hall - attach north or south only. directions = new Directions[] { Directions.North, Directions.South }; } } else { // all other rooms may try to attach from any direction directions = new Directions[] { Directions.North, Directions.East, Directions.South, Directions.West }; } while( doors.Count>0 && connectionDoor==null ) { // pick a door // try to attach to it to the N/E/W/S // update room position accordingly // check room.cells against all other room.cells // break loop when successful FloorTile door = doors[rand.Next(doors.Count)]; doors.Remove(door); if( CheckRoomAgainstGrid(room, door, directions) ) { connectionDoor = door; break; } } // failed to place room if( connectionDoor == null ) return false; //set the connection door foreach( FloorTile cell in room.cells ) if( cell.x==connectionDoor.x && cell.y==connectionDoor.y ) { cell.type = FloorType.DoorOpen; connectionDoor.type = FloorType.DoorOpen; break; } } return true; }