public static GameSpec ForGame(FromGame game) { GameSpec spec = Games.TryGetValue(game, out GameSpec baseSpec) ? baseSpec.Clone() : new GameSpec(); spec.Game = game; return(spec); }
public ItemReader.Result Randomize(RandomizerOptions opt, FromGame game, string gameDir, string outDir) { Console.WriteLine($"Seed: {opt.DisplaySeed}. Options: {string.Join(" ", opt.GetEnabled())}"); string file = game == FromGame.DS3 ? @"fogdist\fog.txt" : @"dist\fog.txt"; IDeserializer deserializer = new DeserializerBuilder().Build(); AnnotationData ann; using (var f = File.OpenText(file)) ann = deserializer.Deserialize <AnnotationData>(f); ann.SetGame(game); Events events = null; if (game == FromGame.DS3) { using (var f = File.OpenText(@"fogdist\locations.txt")) ann.Locations = deserializer.Deserialize <AnnotationData.FogLocations>(f); events = new Events(@"fogdist\Base\ds3-common.emedf.json"); } Graph g = new Graph(); g.Construct(opt, ann); ItemReader.Result item = new ItemReader().FindItems(opt, ann, g, events, gameDir, game); Console.WriteLine(item.Randomized ? $"Key item hash: {item.ItemHash}" : "No key items randomized"); Console.WriteLine(); new GraphConnector().Connect(opt, g, ann); // Actual dryruns stop short of writing modified files if (opt["bonedryrun"]) { return(item); } Console.WriteLine(); if (game == FromGame.DS3) { EventConfig eventConfig; using (var f = File.OpenText(@"fogdist\events.txt")) eventConfig = deserializer.Deserialize <EventConfig>(f); if (opt["eventsyaml"] || opt["events"]) { new GenerateConfig().WriteEventConfig(ann, events, opt); return(item); } new GameDataWriter3().Write(opt, ann, g, gameDir, outDir, events, eventConfig); } else { if (opt["dryrun"]) { Console.WriteLine("Success (dry run)"); return(item); } new GameDataWriter().Write(opt, ann, g, gameDir, game); } return(item); }
public void SetGame(FromGame game) { List <MapSpec> allSpecs = game == FromGame.DS3 ? DS3Specs : DS1Specs; Specs = allSpecs.ToDictionary(s => s.Map, s => s); NameSpecs = allSpecs.ToDictionary(s => s.Name, s => s); }
static void Main(string[] args) { if (args.Length > 0 && !args.Contains("/gui")) { AttachConsole(-1); RandomizerOptions opt = new RandomizerOptions { Seed = new Random().Next() }; foreach (string arg in args) { if (uint.TryParse(arg, out uint s)) { opt.Seed = (int)s; } else { opt[arg] = true; } } FromGame game = args.Contains("ptde") ? FromGame.DS1 : FromGame.DS1R; game = FromGame.DS3; opt.Game = game; string gameDir = ForGame(game).GameDir; if (game == FromGame.DS3) { new Randomizer().Randomize(opt, game, opt["mergemods"] ? gameDir + @"\randomizer" : null, gameDir + @"\fog"); } else { new Randomizer().Randomize(opt, game, gameDir, gameDir); } } else { #if DEBUG AttachConsole(-1); #endif Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // Application.Run(new MainForm()); Application.Run(new MainForm3()); } }
public static CmdType GetCmdType(string esd, FromGame game = FromGame.UNKNOWN) { if (esd.StartsWith("talk") || esd.StartsWith("event")) { return(CmdType.Event); } if (esd.StartsWith("ai")) { return(CmdType.AI); } if (esd.StartsWith("t")) { return(CmdType.Talk); } if (esd.StartsWith("dummy") || exactChr.Contains(esd)) { return(CmdType.Chr); } if (defaultCmds.TryGetValue(game, out CmdType type)) { return(type); } return(CmdType.None); }
private void UpdateExePath() { bool valid = true; string gamePath = null; try { gamePath = Path.GetDirectoryName(exe.Text); if (exe.Text.Trim() == "" || !Directory.Exists(gamePath)) { valid = false; } string exeName = Path.GetFileName(exe.Text).ToLower(); if (exeName == "darksoulsremastered.exe") { game = FromGame.DS1R; } else if (exeName == "darksouls.exe") { game = FromGame.DS1; } else { valid = false; } } catch (ArgumentException) { valid = false; } if (!valid) { game = FromGame.UNKNOWN; restoreButton.Enabled = false; restoreL.Text = ""; language.DataSource = defaultLang; language.Enabled = false; return; } Properties.Settings.Default.Exe = exe.Text; Properties.Settings.Default.Save(); List <string> languages = game == FromGame.DS1R ? ds1rLang : ptdeLang; language.DataSource = languages; language.Enabled = true; if (languageToSet != null && languages.Contains(languageToSet)) { language.SelectedIndex = languages.IndexOf(languageToSet); languageToSet = null; } List <string> files = GameDataWriter.GetAllBaseFiles(game); if (files.Count == 0) { randb.Enabled = false; setStatus($@"Error: FogMod dist\{game} subdirectory is missing", true); } List <string> times = new List <string>(); foreach (string file in files) { string path = $@"{gamePath}\{file}"; string bak = path + ".bak"; if (File.Exists(bak)) { times.Add(File.GetLastWriteTime(bak).ToString("yyyy-MM-dd HH:mm:ss")); } } if (times.Count == 0) { restoreL.Text = "Backups will be created with randomization"; restoreButton.Enabled = false; } else { restoreL.Text = $"{(files.Count == times.Count ? "Backups" : "Partial backups")} from {times.Max()}"; restoreButton.Enabled = true; } }
public GameEditor(FromGame game) { this.Spec = ForGame(game); }
public Result FindItems(RandomizerOptions opt, AnnotationData ann, Graph g, Events events, string gameDir, FromGame game) { Dictionary <string, string> itemsById = ann.KeyItems.ToDictionary(item => item.ID, item => item.Name); Dictionary <string, List <string> > itemAreas = g.ItemAreas; if (ann.LotLocations != null) { GameEditor editor = new GameEditor(game); editor.Spec.GameDir = gameDir; Dictionary <string, PARAM.Layout> layouts = editor.LoadLayouts(); Dictionary <string, PARAM> Params = editor.LoadParams(layouts); Dictionary <int, PARAM.Row> lots = Params["ItemLotParam"].Rows.ToDictionary(r => (int)r.ID, r => r); foreach (KeyValuePair <int, string> entry in ann.LotLocations) { int lot = entry.Key; if (!g.Areas.ContainsKey(entry.Value)) { throw new Exception($"Internal error in lot config for {entry.Key}: {entry.Value} does not exist"); } while (true) { // It's also fine to not have a lot defined as long as all key items are found if (!lots.TryGetValue(lot, out PARAM.Row row)) { break; } for (int i = 1; i <= 8; i++) { int item = (int)row[$"lotItemId0{i}"].Value; if (item == 0) { continue; } int category = (int)row[$"lotItemCategory0{i}"].Value; category = Universe.LotTypes.TryGetValue((uint)category, out int value) ? value : -1; if (category == -1) { continue; } string id = $"{category}:{item}"; if (opt["debuglots"]) { Console.WriteLine($"{entry.Key} in {entry.Value} has {id}"); } if (itemsById.TryGetValue(id, out string name)) { if (itemAreas[name].Count > 0 && itemAreas[name][0] != entry.Value) { throw new Exception($"Item {name} found in both {itemAreas[name][0]} and {entry.Value}"); } itemAreas[name] = new List <string> { entry.Value }; } } lot++; } } } if (ann.Locations != null) { // It's a bit hacky, but should work from anywhere, probably GameEditor editor = new GameEditor(game); editor.Spec.GameDir = $@"fogdist"; editor.Spec.LayoutDir = $@"fogdist\Layouts"; editor.Spec.NameDir = $@"fogdist\Names"; Dictionary <string, PARAM.Layout> layouts = editor.LoadLayouts(); int dragonFlag = -1; Dictionary <string, PARAM> Params = editor.LoadParams(@"fogdist\Base\Data0.bdt", layouts, true); if (gameDir != null) { string paramPath = $@"{gameDir}\Data0.bdt"; if (File.Exists(paramPath)) { Params = editor.LoadParams(paramPath, layouts, true); } string commonEmevdPath = $@"{gameDir}\event\common.emevd.dcx"; if (File.Exists(commonEmevdPath)) { EMEVD commonEmevd = EMEVD.Read(commonEmevdPath); EMEVD.Event flagEvent = commonEmevd.Events.Find(e => e.ID == 13000904); if (flagEvent != null) { Events.Instr check = events.Parse(flagEvent.Instructions[1]); dragonFlag = (int)check[3]; if (opt["debuglots"]) { Console.WriteLine($"Dragon flag: {dragonFlag}"); } } } } Dictionary <int, PARAM.Row> lots = Params["ItemLotParam"].Rows.ToDictionary(r => (int)r.ID, r => r); Dictionary <int, PARAM.Row> shops = Params["ShopLineupParam"].Rows.ToDictionary(r => (int)r.ID, r => r); void setArea(string itemName, List <string> areas) { if (opt["debuglots"]) { Console.WriteLine($"-- name: {itemName}"); } if (itemAreas[itemName].Count > 0 && !itemAreas[itemName].SequenceEqual(areas)) { throw new Exception($"Item {itemName} found in both {string.Join(",", itemAreas[itemName])} and {string.Join(",", areas)}"); } itemAreas[itemName] = areas; } foreach (KeyItemLoc loc in ann.Locations.Items) { List <string> areas = loc.Area.Split(' ').ToList(); if (!areas.All(a => g.Areas.ContainsKey(a) || itemAreas.ContainsKey(a))) { // Currently happens with multi-area intersection lots/shops throw new Exception($"Warning: Areas not found for {loc.Area} - {loc.DebugText[0]}"); } List <int> lotIds = loc.Lots == null ? new List <int>() : loc.Lots.Split(' ').Select(i => int.Parse(i)).ToList(); foreach (int baseLot in lotIds) { int lot = baseLot; while (true) { // It's also fine to not have a lot defined as long as all key items are found if (!lots.TryGetValue(lot, out PARAM.Row row)) { break; } for (int i = 1; i <= 8; i++) { int item = (int)row[$"ItemLotId{i}"].Value; if (item == 0) { continue; } uint category = (uint)row[$"LotItemCategory0{i}"].Value; if (!Universe.LotTypes.TryGetValue(category, out int catVal)) { continue; } string id = $"{catVal}:{item}"; if (opt["debuglots"]) { Console.WriteLine($"lot {lot} in {loc.Area} has {id}"); } if (itemsById.TryGetValue(id, out string name)) { setArea(name, areas); } } if (dragonFlag > 0 && (int)row["getItemFlagId"].Value == dragonFlag) { setArea("pathofthedragon", areas); } lot++; } } List <int> shopIds = loc.Shops == null ? new List <int>() : loc.Shops.Split(' ').Select(i => int.Parse(i)).ToList(); foreach (int shopId in shopIds) { // Not as fine for a shop to be missing, but also whatever if (!shops.TryGetValue(shopId, out PARAM.Row row)) { continue; } int item = (int)row["EquipId"].Value; int catVal = (byte)row["equipType"].Value; string id = $"{catVal}:{item}"; if (opt["debuglots"]) { Console.WriteLine($"shop {shopId} in {loc.Area} has {id}"); } if (itemsById.TryGetValue(id, out string name)) { setArea(name, areas); } if (dragonFlag > 0 && (int)row["EventFlag"].Value == dragonFlag) { setArea("pathofthedragon", areas); } } } } // lots:.*[1-9]\r // Iterative approach for items which depend simply on other items // Recursion would look a lot nicer but lazy bool itemExpanded; do { itemExpanded = false; foreach (KeyValuePair <string, List <string> > entry in itemAreas) { foreach (string dep in entry.Value.ToList()) { if (itemAreas.TryGetValue(dep, out List <string> deps)) { entry.Value.Remove(dep); entry.Value.AddRange(deps); itemExpanded = true; } } } }while (itemExpanded); if (opt["explain"] || opt["debuglots"]) { foreach (Item item in ann.KeyItems) { Console.WriteLine($"{item.Name} {item.ID}: default {item.Area}, found [{string.Join(", ", itemAreas[item.Name])}]"); } } // Collect items in graph SortedSet <string> itemRecord = new SortedSet <string>(); bool randomized = false; foreach (Item item in ann.KeyItems) { if (itemAreas[item.Name].Count == 0) { if (item.HasTag("randomonly")) { itemAreas[item.Name] = new List <string> { item.Area }; } else if (item.HasTag("hard") && !opt["hard"]) { continue; } else { throw new Exception($"Couldn't find {item.Name} in item lots"); } } List <string> areas = itemAreas[item.Name]; foreach (string area in areas) { g.Nodes[area].Items.Add(item.Name); } if (!item.HasTag("randomonly")) { if (areas.Count > 1 || areas[0] != item.Area) { randomized = true; } itemRecord.Add($"{item.Name}={string.Join(",", areas)}"); } } return(new Result { Randomized = randomized, ItemHash = (RandomizerOptions.JavaStringHash($"{string.Join(";", itemRecord)}") % 99999).ToString().PadLeft(5, '0') }); }