/// <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> /// Remove unwanted artifact from the map : door leading to nowhere, cul-de-sac... /// This is done by replacement rules with chance = 100 /// </summary> /// <param name="map"></param> private void Clean(Map map) { Logger.Info($"Cleaning the map from unwanted artifact", Logger.LogAction.PUSH); // change "unknown" to "wall" map.ReplaceAll('?', '#'); bool modified = true; // get all rentries that are always used... List <ReplacementRule> always = _modifications.collection.FindAll(template => (template.Chance == 100)); Logger.Info($"{always.Count} rules found"); always.Sort( delegate(ReplacementRule x, ReplacementRule y) { if (x.Priority == y.Priority) { return(0); } if (x.Priority > y.Priority) { return(1); } else { return(-1); } } ); while (modified) { modified = false; foreach (ReplacementRule rule in always) { modified = modified || map.ReplaceAll(rule.InitialContent, rule.ReplacementContent); } if (Debug) { CharUtils.saveAsImage($"./assets/map{operationCount++}.png", map.Content); } } Logger.Pop(); }
/// <summary> /// Read a pattern in the "0" FileFormat /// First line is XSize ///Second Line is YSize ///Third line are operation to generate Mirror pattern (Rotate : X, H Mirror : X, V Mirror : Y) ///Followed by YSize lines of XSize chars /// </summary> /// <param name="reader"></param> public static void Read_FileFormat_0(StreamReader reader, MapTemplateList templates) { try { int xsize = 0; int ysize = 0; Int32.TryParse(reader.ReadLine(), out xsize); Int32.TryParse(reader.ReadLine(), out ysize); string operations = reader.ReadLine(); char[,] roomData = loadData(reader, xsize, ysize); // if requested, create mirrored copies List <char[, ]> mirrors = CharUtils.CreateMirrors(roomData, operations); int count = 0; int sourceId = 0; MapTemplate tmp; foreach (char[,] copy in mirrors) { if (count == 0) { tmp = new MapTemplate(copy); sourceId = tmp.Id; CharUtils.saveAsImage($"./assets/images/{templates._name}_{tmp.Id}.png", copy); } else { tmp = new MapTemplate(copy, sourceId); } templates.Add(tmp); //CharUtils.saveAsImage($"./assets/images/{templates._name}_{tmp.Id}.png", copy); count++; } } catch (Exception e) { Logger.Error(e.Message); Console.WriteLine(e.Message); } }
static void Main(string[] args) { Logger.initialisation(); // get char groups CharGroupsLoader.loadFromDirectory("./assets/"); // get the rooms & doors template MapTemplateList rooms = MapTemplateLoader.loadFromDirectory("./assets/rooms", "rooms"); // get the rooms & doors template MapTemplateList doors = MapTemplateLoader.loadFromDirectory("./assets/doors", "doors"); // get the cleaning template rules ReplacementRuleList modifications = ReplacementRuleLoader.loadFromDirectory("./assets/modifications", "modifications"); // create the map Map map = new Map(75, 75); // create the generator & call it MapGenerator1 generator = new MapGenerator1(rooms, doors, modifications); generator.GenerateMap(map); CharUtils.saveAsImage("./assets/map.png", map.Content); }
/// <summary> /// replace some part of the map by others, based on pattern matching and randomness /// </summary> /// <param name="map"></param> private void Decorate(Map map) { Logger.Info($"Modifiying the map ", Logger.LogAction.PUSH); // get all rentries that are always used... List <ReplacementRule> sometimes = _modifications.collection.FindAll(template => (template.Chance != 100)); Logger.Info($"{sometimes.Count} rules found"); sometimes.Sort( delegate(ReplacementRule x, ReplacementRule y) { if (x.Priority == y.Priority) { return(0); } if (x.Priority > y.Priority) { return(1); } else { return(-1); } } ); foreach (ReplacementRule rule in sometimes) { Logger.Info($" replacement of {rule.InitialContent.Id} by {rule.ReplacementContent.Id} with {rule.Chance}% chance "); map.ReplaceAll(rule.InitialContent, rule.ReplacementContent, rule.Chance, ""); if (Debug) { CharUtils.saveAsImage($"./assets/map{operationCount++}.png", map.Content); } } Logger.Pop(); }