//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Adds an exit to the room hooked to another generic room. </summary> /// /// <remarks> Darrellp, 9/28/2011. </remarks> /// /// <param name="groom"> The room to be joined to this one. </param> /// <param name="location"> The location the exit to groom will be. </param> /// /// <returns> The character allocated for the new exit. </returns> //////////////////////////////////////////////////////////////////////////////////////////////////// internal char AddExit(GenericRoom groom, MapCoordinates location) { char exitChar = (char)('a' + Exits.Count); Exits.Add(groom); this[location] = exitChar; ExitMap[location] = groom; return(exitChar); }
private static void AssignTilesInRoom(IRoomsMap map, GenericRoom groom) { // Is this room being newly added to the map? if (map.Rooms.Add(groom)) { // For each tile in the room foreach (var tileLocation in groom.Tiles) { // Assign the room to that tile map[tileLocation].Room = groom; } } }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Updates the rooms connected to groom to point to us. </summary> /// /// <remarks> Darrellp, 9/28/2011. </remarks> /// /// <param name="groom"> The room whose connected rooms are to be joined to this one. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private void UpdateConnectedRoomsToPointToUs(GenericRoom groom) { // For each exit in the old room foreach (var exitInfo in groom.ExitMap) { // Get the room on the other side MapCoordinates location = exitInfo.Key; GenericRoom groomExitedTo = exitInfo.Value; int indexToUs = groomExitedTo[location] - 'a'; // and point it back to us groomExitedTo.Exits[indexToUs] = this; } }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Excavates between two rooms. </summary> /// /// <remarks> Variables named from the perspective of dir being vertical. Darrellp, 9/18/2011. </remarks> /// /// <param name="map"> The map to be excavated. </param> /// <param name="roomTop"> The first room. </param> /// <param name="roomBottom"> The second room. </param> /// <param name="dir"> The direction to excavate in. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private void ExcavateCorridor(IRoomsMap map, RectangularRoom roomTop, RectangularRoom roomBottom, Dir dir) { // Locals MapCoordinates bottomEntrance, topEntrance; // Get the entrances to each room GetEntrances(roomTop, roomBottom, dir, out topEntrance, out bottomEntrance); // Allocate the generic room int genericWidth = Math.Abs(topEntrance.Column - bottomEntrance.Column) + 1; int genericHeight = Math.Abs(topEntrance.Row - bottomEntrance.Row) + 1; int genericLeft = Math.Min(topEntrance.Column, bottomEntrance.Column); int genericBottom = Math.Min(topEntrance.Row, bottomEntrance.Row); MapCoordinates genericLocation = new MapCoordinates(genericLeft, genericBottom); GenericCorridor corridor = new GenericCorridor(genericWidth, genericHeight, genericLocation); // Excavate a connection between the two rooms CreateBend(map, dir, topEntrance, bottomEntrance, corridor); // Put the exits in the appropriate generic rooms GenericRoom groomTop = _mapRoomToGenericRooms[roomTop]; GenericRoom groomBottom = _mapRoomToGenericRooms[roomBottom]; corridor.AddExit(groomTop, topEntrance); corridor.AddExit(groomBottom, bottomEntrance); groomTop.AddExit(corridor, topEntrance); groomBottom.AddExit(corridor, bottomEntrance); // Should we put a door in the top room? if (_rnd.Next(100) < _pctDoorChance) { // Place the door map[topEntrance].Terrain = TerrainType.Door; } // Should we put a door in the bottom room? if (_rnd.Next(100) < _pctDoorChance) { // Place the door map[bottomEntrance].Terrain = TerrainType.Door; } }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Combine two generic rooms </summary> /// /// <remarks> Darrellp, 9/27/2011. </remarks> /// /// <param name="groom"> The room to be joined to this one. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// internal void CombineWith(GenericRoom groom) { // Clone into a temporary room GenericRoom roomTemp = new GenericRoom(Layout, Location, Exits); // Get the new and old locations, sizes int newLeft = Math.Min(Left, groom.Left); int newRight = Math.Max(Right, groom.Right); int newTop = Math.Min(Top, groom.Top); int newBottom = Math.Max(Bottom, groom.Bottom); int newHeight = newBottom - newTop + 1; int newWidth = newRight - newLeft + 1; // Set our new location Location = new MapCoordinates(newLeft, newTop); // Clear our exits // They'll come back in from the cloned room Exits = new List <GenericRoom>(); // Allocate a new layout array Layout = new char[newWidth][]; // For each column for (int iColumn = 0; iColumn < newWidth; iColumn++) { // Allocate the column Layout[iColumn] = new char[newHeight]; } // Move the clone's data into ourself TransferTerrain(roomTemp); // Move the other room's data into ourself TransferTerrain(groom); // Update pointers for any rooms which connected to groom UpdateConnectedRoomsToPointToUs(groom); // Set up our exit map MapExitsToRooms(); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Transfer terrain. </summary> /// /// <remarks> This only affects the _layout field. Darrellp, 9/27/2011. </remarks> /// /// <param name="groom"> The room to be joined to this one. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private void TransferTerrain(GenericRoom groom) { // Locals int mapColumn; int localColumn; // For each original column for (localColumn = 0, mapColumn = groom.Left; localColumn < groom.Width; localColumn++, mapColumn++) { // More locals int mapRow; int localRow; // For each original row for (localRow = 0, mapRow = groom.Top; localRow < groom.Height; localRow++, mapRow++) { // Get the terrain for this location char character = groom.Layout[localColumn][localRow]; // Is this an exit? if (character >= 'a' && character <= 'z') { // Add it to our list of exits int iRoom = (char)(character - 'a'); GenericRoom groomExitedTo = groom.Exits[iRoom]; character = AddExit(groomExitedTo, new MapCoordinates(mapColumn, mapRow)); } // Is it non-null? if (character != '\0') { // Place the new terrain this[mapColumn, mapRow] = character; } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Adds a room to our room list. </summary> /// /// <remarks> Darrellp, 10/6/2011. </remarks> /// /// <param name="groom"> The generic room to be added. </param> /// /// <returns> true if the room has already been added, false if it hasn't. </returns> //////////////////////////////////////////////////////////////////////////////////////////////////// public bool AddRoom(GenericRoom groom) { return(Rooms.Add(groom)); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Excavate between connected rooms in a grid connection. </summary> /// /// <remarks> Variables named from the perspective that dir is vertical Darrellp, 9/19/2011. </remarks> /// /// <param name="map"> The map to be excavated. </param> /// <param name="dir"> The direction the merge will take place in. </param> /// <param name="topEntrance"> The small coordinate entrance. </param> /// <param name="bottomEntrance"> The large coordinate entrance. </param> /// <param name="groom"> The room being prepared for this corridor. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private void CreateBend(IRoomsMap map, Dir dir, MapCoordinates topEntrance, MapCoordinates bottomEntrance, GenericRoom groom) { // locals Dir otherDir = MapCoordinates.OtherDirection(dir); int startRow = topEntrance[dir]; int endRow = bottomEntrance[dir]; int startColumn = topEntrance[otherDir]; int endColumn = bottomEntrance[otherDir]; // Determine bend location int bendRow = _rnd.Next(startRow + 1, endRow); // Excavate the bend between the two rooms ExcavateBend(map, startColumn, endColumn, startRow, endRow, bendRow, groom, dir); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Excavate bend. </summary> /// /// <remarks> /// "Perpindicular" here refers to the coordinate perpindicular to the orientation of the two /// rooms. If the rooms are oriented vertically then perpindicular refers to the horizontal (x) /// coordinate wo that startPerpindicular is the starting column. If they're oriented vertically, /// startPerpindicular is the starting row. Parallel refers to the coordinate parallel to the /// orientation. Bend is always in the perpindicular coordinate. Unidirectional but named as /// though dir was vertical. Darrellp, 9/18/2011. /// </remarks> /// /// <param name="map"> The map to be excavated. </param> /// <param name="startColumn"> The start perpindicular. </param> /// <param name="endColumn"> The end perpindicular. </param> /// <param name="startRow"> The start parallel. </param> /// <param name="endRow"> The end parallel. </param> /// <param name="bend"> The bend coordinate. </param> /// <param name="groom"> The room being prepared for this corridor. </param> /// <param name="dir"> The direction the bend is supposed to run. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private static void ExcavateBend(IRoomsMap map, int startColumn, int endColumn, int startRow, int endRow, int bend, GenericRoom groom, Dir dir) { Dir otherDir = MapCoordinates.OtherDirection(dir); // Create corridor to the bend ExcavateCorridorRun(map, startColumn, startRow, bend, groom, dir); // Create the cross corridor at the bend ExcavateCorridorRun(map, bend, startColumn, endColumn, groom, otherDir); // Create the corridor from the bend to the destination ExcavateCorridorRun(map, endColumn, bend, endRow, groom, dir); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Excavate a straight corridor run either vertically or horizontally. </summary> /// /// <remarks> /// Excavates from (startParallel, perpindicular) to (endParallel, perpindicular) inclusive if /// fVertical. If not fVertical, swap coordinates. start and end parallel coordinates do not /// have to be in numerical order. This is a unidirectional function but, as usual, names are /// named as though dir was vertical. Darrellp, 9/19/2011. /// </remarks> /// /// <param name="map"> The map to be excavated. </param> /// <param name="column"> The perpindicular coordinate. </param> /// <param name="endRow1"> The starting parallel coordinate. </param> /// <param name="endRow2"> The ending parallel coordinate. </param> /// <param name="groom"> The room being prepared for this corridor. </param> /// <param name="dir"> The direction of the corridor. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private static void ExcavateCorridorRun(IRoomsMap map, int column, int endRow1, int endRow2, GenericRoom groom, Dir dir) { // We work with small and large coords rather than start and end int startRow = Math.Min(endRow1, endRow2); int endRow = Math.Max(endRow1, endRow2); char floorChar = TerrainFactory.TerrainToChar(TerrainType.Floor); // Create the starting location MapCoordinates currentLocation = MapCoordinates.CreateUndirectional(startRow, column, dir); // For each row in the run for (int iRow = startRow; iRow <= endRow; iRow++) { // Place our terrain currentLocation[dir] = iRow; map[currentLocation].Terrain = TerrainType.Floor; groom[currentLocation] = floorChar; } }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Excavate a merge between two rooms. </summary> /// /// <remarks> /// Names are named as though dir was vertical and dirOther horizontal. Darrellp, 9/22/2011. /// </remarks> /// /// <param name="map"> The map. </param> /// <param name="topRoom"> The top room. </param> /// <param name="bottomRoom"> The bottom room. </param> /// <param name="dir"> The dir. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private void ExcavateMerge(IRoomsMap map, RectangularRoom topRoom, RectangularRoom bottomRoom, Dir dir) { // Get the opposite direction Dir dirOther = MapCoordinates.OtherDirection(dir); // Are the rooms unmergable? if (!CheckOverlap(topRoom, bottomRoom, dirOther)) { // Should have caught this in MergeTwoRooms - throw exception throw new RogueException("Non-overlapping rooms made it to ExcavateMerge"); } // Get the appropriate coordinates int topRoomsLeft = topRoom.Location[dirOther]; int topRoomsRight = topRoomsLeft + topRoom.Size(dirOther) - 1; int bottomRoomsLeft = bottomRoom.Location[dirOther]; int bottomRoomsRight = bottomRoomsLeft + bottomRoom.Size(dirOther) - 1; // Get the high and low points of the overlap int overlapLeft = Math.Max(topRoomsLeft, bottomRoomsLeft) + 1; int overlapRight = Math.Min(topRoomsRight, bottomRoomsRight) - 1; // Create our new merged generic room GenericRoom groomTop = _mapRoomToGenericRooms[topRoom]; GenericRoom groomBottom = _mapRoomToGenericRooms[bottomRoom]; groomTop.CombineWith(groomBottom); // For each column in the grid foreach (RectangularRoom[] roomColumn in _rooms) { // For each row in the grid for (int iRow = 0; iRow < _rooms[0].Length; iRow++) { // Get the rect room at that spot RectangularRoom room = roomColumn[iRow]; // Is it mapped to our defunct bottom room? if (_mapRoomToGenericRooms[room] == groomBottom) { // Map it to our shiny new top room _mapRoomToGenericRooms[room] = groomTop; } } } // Get the location we're going to start the clearing at int topRoomsBottom = topRoom.Location[dir] + topRoom.Size(dir) - 1; MapCoordinates currentLocation = MapCoordinates.CreateUndirectional(topRoomsBottom, overlapLeft, dir); char floorChar = TerrainFactory.TerrainToChar(TerrainType.Floor); // For each spot along the overlap for (int iCol = overlapLeft; iCol <= overlapRight; iCol++) { // Clear out the two walls of the abutting rooms currentLocation[dirOther] = iCol; map[currentLocation].Terrain = TerrainType.Floor; groomTop[currentLocation] = floorChar; currentLocation[dir] = topRoomsBottom + 1; map[currentLocation].Terrain = TerrainType.Floor; groomTop[currentLocation] = floorChar; currentLocation[dir] = topRoomsBottom; } Debug.Assert(groomBottom == groomTop || !_mapRoomToGenericRooms.ContainsValue(groomBottom)); }