public void Randomize() { if (model.RandomizeMonsters || model.RandomizeBosses) { var dungeons = new[] { "cove", "crypts", "warrens", "weald" }; var levels = new[] { 1, 3, 5 }; foreach (var dungeon in dungeons) { var dungeonsDir = model.ModDirectory.CreateSubdirectory("dungeons"); var dungeonDir = dungeonsDir.CreateSubdirectory(dungeon); } foreach (var level in levels) { var dungeonFiles = dungeons.Select(dungeon => Darkest.LoadFromFile(model.GetGameDataPath(Path.Combine("dungeons", dungeon, $"{dungeon}.{level}.mash.darkest")))); if (model.RandomizeMonsters) { var(hallEnemies, roomEnemies, stallEnemies) = GetAllEnemies(dungeonFiles); var hallEnemyReplacements = ShuffleMap(hallEnemies); var roomEnemyReplacements = ShuffleMap(roomEnemies); var stallEnemyReplacements = ShuffleMap(stallEnemies); dungeonFiles = ReplaceEnemies(dungeonFiles, hallEnemyReplacements, roomEnemyReplacements, stallEnemyReplacements); } if (model.RandomizeBosses) { // Exclude shrieker! var bossLayouts = GetAllBossLayouts(dungeonFiles); var shuffledBossLayouts = bossLayouts.Shuffle(random); dungeonFiles = ReplaceBosses(dungeonFiles, shuffledBossLayouts); var questTypeFile = JsonNode.Parse(File.ReadAllText(model.GetGameDataPath(Path.Combine("campaign", "quest", "quest.types.json")))) ?.AsObject(); if (questTypeFile == null) { throw new Exception("quest.types.json could not be parsed."); } var bossLayoutConversion = bossLayouts.Zip(shuffledBossLayouts, (original, shuffled) => (original, shuffled)); foreach (var goal in questTypeFile["goals"] !.AsArray()) { if (goal == null) { continue; } var data = goal["data"]?.AsObject(); if (data == null) { continue; } var monsterClassIds = data["monster_class_ids"]?.AsArray(); if (monsterClassIds != null) { data["monster_class_ids"] = bossLayoutConversion .FirstOrDefault(bossLayout => monsterClassIds .Any(questMonster => bossLayout.original.Contains((string)questMonster !))) switch { (_, null) => goal["data"] !["monster_class_ids"],
private void ReadBaseGameData() { Monsters = new Dictionary <string, Monster>(); foreach (var monsterType in Directory.GetDirectories(Path.Combine(DDPath, "monsters")).Select(Path.GetFileName)) { if (monsterType == null) { continue; } foreach (var monsterName in Directory.GetDirectories(Path.Combine(DDPath, "monsters", monsterType)) .Select(Path.GetFileName) .Where(x => x != null && x.StartsWith(monsterType))) { if (monsterName == null) { continue; // Extraneous but makes NRT stuff go away } Monsters[monsterName] = Monster.FromDarkest( monsterName, Darkest.LoadFromFile(Path.Combine(DDPath, "monsters", monsterType, monsterName, $"{monsterName}.info.darkest")) ); } } HeroNames = Directory.GetDirectories(Path.Combine(DDPath, "heroes")).Select(x => Path.GetFileName(x)).ToArray(); }
public void Randomize() { if (model.RandomizeCampingSkills) { var file = JsonNode.Parse(File.ReadAllText(model.GetGameDataPath(Path.Combine("raid", "camping", "default.camping_skills.json")))) ?.AsObject(); if (file == null || file["skills"] is not JsonArray skills || skills.Count < 7) { throw new Exception("default.camping_skills.json could not be parsed properly."); } // Make in-game layout look prettier :) file["configuration"] !.AsObject()["class_specific_number_of_classes_threshold"] = JsonValue.Create(100); var layoutFile = Darkest.LoadFromFile(model.GetGameDataPath(Path.Combine("campaign", "town", "buildings", "camping_trainer", "camping_trainer.layout.darkest"))); layoutFile.Replace("camping_trainer_class_specific_skill_grid_layout", "skill_spacing", (x, _, i) => i == 1 ? "170" : x) .WriteToFile(Path.Combine( model.ModDirectory .CreateSubdirectory("campaign") .CreateSubdirectory("town") .CreateSubdirectory("buildings") .CreateSubdirectory("camping_trainer") .FullName, "camping_trainer.layout.darkest")); foreach (var skill in skills) { skill !.AsObject()["hero_classes"] = new JsonArray(); } foreach (var hero in model.HeroNames) { HashSet <int> skillIndicies = new HashSet <int>(); while (skillIndicies.Count < 7) { skillIndicies.Add(random.Next(0, skills.Count)); } foreach (var skillIndex in skillIndicies) { skills[skillIndex]?.AsObject()["hero_classes"]?.AsArray().Add(hero); } } File.WriteAllText(Path.Combine( model.ModDirectory .CreateSubdirectory("raid") .CreateSubdirectory("camping") .FullName, "default.camping_skills.json"), file.ToJsonString(new() { WriteIndented = true })); } }
public void Randomize() { if (model.RandomizeHeroStats > 0) { var heroesDir = model.ModDirectory.CreateSubdirectory("heroes"); foreach (var heroName in model.HeroNames) { var res = GenerateBalancedModifiers(7).Select(x => Math.Round(x * baseResistance).ToString()).ToArray(); var battle = GenerateBalancedModifiers(5); var darkest = Darkest.LoadFromFile(model.GetGameDataPath(Path.Combine("heroes", heroName, $"{heroName}.info.darkest"))); var randomized = darkest.Replace(new[] {
public void Randomize() { if (model.RandomizeHeroSkills) { var heroesDir = model.ModDirectory.CreateSubdirectory("heroes"); foreach (var hero in model.HeroNames) { heroesDir.CreateSubdirectory(hero); } var heroSkillMappings = GenerateHeroSkillMappings(); var heroFiles = model.HeroNames.ToDictionary( name => name, name => ( info: Darkest.LoadFromFile(model.GetGameDataPath(Path.Combine("heroes", name, $"{name}.info.darkest"))), art: Darkest.LoadFromFile(model.GetGameDataPath(Path.Combine("heroes", name, $"{name}.art.darkest"))) )); Darkest highwaymanInfo = null !; Darkest crusaderInfo = null !; XmlDocument heroStrings = new XmlDocument(); heroStrings.Load(model.GetGameDataPath(Path.Combine("localization", "heroes.string_table.xml"))); var heroSkillNames = heroFiles.ToDictionary(p => p.Key, p => GetSkillsInOrder(p.Value.art)); foreach (var hero in model.HeroNames) { var(info, art) = SwapCombatSkills(heroFiles, hero, heroSkillMappings); info.WriteToFile(Path.Combine(model.ModDirectory.FullName, "heroes", hero, $"{hero}.info.darkest")); art.WriteToFile(Path.Combine(model.ModDirectory.FullName, "heroes", hero, $"{hero}.art.darkest")); if (hero == "highwayman") { highwaymanInfo = info; } else if (hero == "crusader") { crusaderInfo = info; } var skillNames = heroSkillNames[hero]; // Localization for (int i = 0; i < 7; i++) { if (heroSkillMappings[hero][i] == hero) { continue; } var combatNodes = heroStrings.SelectNodes($"//entry[@id='combat_skill_name_{heroSkillMappings[hero][i]}_{heroSkillNames[heroSkillMappings[hero][i]][i]}']") ! .Cast <XmlNode>() .Zip(heroStrings.SelectNodes($"//entry[@id='combat_skill_name_{hero}_{skillNames[i]}']") ! .Cast <XmlNode>(), (a, b) => (from: b, to: a)); foreach (var(from, to) in combatNodes) { var originalAttr = heroStrings.CreateAttribute("original"); originalAttr.Value = from !.InnerXml; from !.Attributes !.Append(originalAttr); if (to?.Attributes?.GetNamedItem("original") is XmlAttribute a) { from !.InnerXml = a.Value; } else { from !.InnerXml = to !.InnerXml; } } var upgradeNodes = heroStrings.SelectNodes($"//entry[@id='upgrade_tree_name_{heroSkillMappings[hero][i]}.{heroSkillNames[heroSkillMappings[hero][i]][i]}']") ! .Cast <XmlNode>() .Zip(heroStrings.SelectNodes($"//entry[@id='upgrade_tree_name_{hero}.{skillNames[i]}']") ! .Cast <XmlNode>(), (a, b) => (from: b, to: a)); foreach (var(from, to) in upgradeNodes) { var originalAttr = heroStrings.CreateAttribute("original"); originalAttr.Value = from !.InnerXml; from !.Attributes !.Append(originalAttr); if (to?.Attributes?.GetNamedItem("original") is XmlAttribute a) { from !.InnerXml = a.Value; } else { from !.InnerXml = to !.InnerXml; } } } } foreach (var node in heroStrings !.SelectNodes("//*[@original]") !.Cast <XmlNode>()) { node?.Attributes !.RemoveNamedItem("original"); } heroStrings.Save(Path.Combine(model.ModDirectory.CreateSubdirectory("localization").FullName, "heroes.string_table.xml")); SwapSkillIcons(heroSkillMappings); //UpdateStartingSave(highwaymanInfo, crusaderInfo); } }