/// <summary> /// Generate a dungeon in the given map, from the objects in the lists given in the constructor /// </summary> /// <param name="map">the map to generate the dungeon in</param> public void GenerateMap(Map map) { Logger.Info($"Generation for map size {map.XSize}x{map.YSize}"); operationCount = 0; List <PatternPosition> availablesExits = new List <PatternPosition>(); List <PatternPosition> usedRooms = new List <PatternPosition>(); // get a random entry PatternPosition entry = generateEntry(map, _doors); GenerateMap(map, entry); }
/// <summary> ///Generate a random entry to be placed on the map /// </summary> /// <param name="map">the map where the entry would be placed</param> /// <param name="doors">the list of available door type</param> /// <returns>a position & door type</returns> private PatternPosition generateEntry(Map map, MapTemplateList doors) { MapTemplate door = doors.getTemplate(rnd.Next(doors.Count())); PatternPosition entry = new PatternPosition(); entry.y = rnd.Next(1, map.XSize); entry.x = rnd.Next(1, map.YSize); entry.id = door.Id; Logger.Info($"Putting Entry door type {door.Id} at {entry.x}x{entry.y}"); return(entry); }
/// <summary> /// Place a room on the map. /// Add the exits of the room to the list of available exits for the map generations, if needed /// </summary> /// <param name="room"></param> /// <param name="xpos"></param> /// <param name="ypos"></param> /// <param name="availablesExits"></param> /// <param name="usedRooms"></param> /// <returns>true</returns> private bool PlaceRoom(Map map, MapTemplate room, int xpos, int ypos, List <PatternPosition> availablesExits, List <PatternPosition> usedRooms) { Logger.Info($"placement of {room.Id} at {xpos}x{ypos}", Logger.LogAction.PUSH); // put the content of the room on the map. for (int y1 = 0; y1 < room.YSize; y1++) { for (int x1 = 0; x1 < room.XSize; x1++) { if (room.Content[y1, x1] != '?') { map.Content[ypos + y1, xpos + x1] = room.Content[y1, x1]; } } } // store the room so that we do not try the same room for one of its own exit // (as it may work, as the 2 rooms would be superposed) PatternPosition newRoom = new PatternPosition(); newRoom.x = xpos; newRoom.y = ypos; newRoom.id = room.SourceId; usedRooms.Add(newRoom); // for all doors from this room, either add it to the 'available' list, or remove it if allready present // (this is a common exit with a previous room, and is now used) foreach (MapTemplate doorPattern in _doors) { //find all occurnece of this kind of doors in the room List <Position> doorsList = doorPattern.Matches(room, true); doorsList.Shuffle(); foreach (Position position in doorsList) { PatternPosition roomDoor = new PatternPosition(); roomDoor.x = position.X + xpos; roomDoor.y = position.Y + ypos; roomDoor.id = doorPattern.Id; // if already present in the availables list : common exit with a previous room (remove it), if (availablesExits.FindAll(exit => (roomDoor.x == exit.x && roomDoor.y == exit.y && roomDoor.id == exit.id)).Count > 0) { availablesExits.RemoveAll(exit => (roomDoor.x == exit.x && roomDoor.y == exit.y && roomDoor.id == exit.id)); } // otherwise add it else { availablesExits.Add(roomDoor); } } } Logger.Pop(); return(true); }
/// <summary> /// Generate a dungeon in the given map, from the objects in the lists given in the constructor /// </summary> /// <param name="map">the map to generate the dungeon in</param> /// <param name="entry">the entry (door + position) used to start the dungeon</param> public void GenerateMap(Map map, PatternPosition entry) { List <PatternPosition> availablesExits = new List <PatternPosition>(); List <PatternPosition> usedRooms = new List <PatternPosition>(); List <PatternPosition> rejectedExits = new List <PatternPosition>(); // use given entry as the initial entry/door map.Place(_doors.Find(entry.id), entry.x, entry.y); availablesExits.Add(entry); // also add it to the toremove (it will not be used by another room...) // since it's the first, it will be the "Up" (see ManageEntries) rejectedExits.Add(entry); if (Debug) { CharUtils.saveAsImage($"./assets/map{operationCount++}.png", map.Content); } // While there are not checked exits while (availablesExits.Count > 0) { // Select one door on the map (random) //PatternPosition exit = availablesExits[rnd.Next(0, availablesExits.Count)]; // Select one door on the map (breadth first) PatternPosition exit = availablesExits[0]; // Select one door on the map (deapth first) //PatternPosition exit = availablesExits[availablesExits.Count - 1]; // try to place a room to this exit this.PlaceRoomForDoor(map, exit, availablesExits, usedRooms, rejectedExits); if (Debug) { CharUtils.saveAsImage($"./assets/map{operationCount++}.png", map.Content); } Logger.Pop(); } // generate an entry and exit ManageEntries(map, rejectedExits); // remove unwanted artifacts (not used doors...) Clean(map); // place some new element / remove some based on pattern Decorate(map); Logger.Pop(); }
/// <summary> /// Select two non used doors and set them as exit of the map; /// </summary> /// <param name="map">the map to get the entries on</param> /// <param name="rejectedExits">list of non used doors</param> private void ManageEntries(Map map, List <PatternPosition> rejectedExits) { // choose the exit PatternPosition exitPos = rejectedExits[0]; // get the template MapTemplate door = _doors.Find(exitPos.id); // duplicate it and change it MapTemplate exit = new MapTemplate(door); CharUtils.ReplaceAll(exit.Content, '=', 'U'); // update the map map.Place(exit, exitPos.x, exitPos.y); map.UpExit = exitPos; exitPos = rejectedExits[rejectedExits.Count - 1]; // get the template door = _doors.Find(exitPos.id); // duplicate it and change it exit = new MapTemplate(door); CharUtils.ReplaceAll(exit.Content, '=', 'D'); // update the map map.Place(exit, exitPos.x, exitPos.y); map.DownExit = exitPos; }
/// <summary> /// Try to place a room, given an exit position ( ie door ). The room will be taken in the list of room having this kind of exit. /// if a room is placed, new exits will be adde to the list, and old one (common to another room) removed. /// </summary> /// <param name="exit">the exit position & pattern</param> /// <param name="availablesExits">the list of available exit</param> /// <returns>true if a room was placed</returns> private bool PlaceRoomForDoor(Map map, PatternPosition exit, List <PatternPosition> availablesExits, List <PatternPosition> usedRooms, List <PatternPosition> rejectedExits) { ; MapTemplateList possiblesRooms = doorGroups[exit.id]; possiblesRooms.collection.Shuffle(); possiblesRooms.collection.Sort( delegate(MapTemplate x, MapTemplate y) { var xx = x.SortValue - x.Usage; var yy = y.SortValue - y.Usage; if (xx == yy) { return(0); } if (xx < yy) { return(1); } else { return(-1); } } ); bool placed = false; // for all room that contains our exit //possiblesRooms.Reset(); foreach (MapTemplate room in possiblesRooms) { // get all position in this room of the exi we're working on List <Position> possibleExits = _doors.Find(exit.id).Matches(room, true); possibleExits.Shuffle(); foreach (Position pos in possibleExits) { // check if the room can be put, mapping the choosen room exit with the exit we were given if (CheckRoom(map, room, exit.x - pos.X, exit.y - pos.Y, usedRooms)) { // place the room PlaceRoom(map, room, exit.x - pos.X, exit.y - pos.Y, availablesExits, usedRooms); // change all usage of room with the same SourceId UpdateUsage(room); // flag the map as modified placed = true; break; // leave the search for a valid exit } } // if a room has been placed onto the exit, leave the search for a room if (placed) { break; } } // if no room found, remove the exit from the list of available (if placed, this has already be done) if (!placed) { availablesExits.RemoveAll(template => (exit.x == template.x && exit.y == template.y && exit.id == template.id)); rejectedExits.Add(exit); } return(placed); }