public static void Load() { BuildSets.Clear(); Houses.Clear(); Guardlines.Clear(); FileInfo[] files = _definitionsPath.GetFiles("*.txt").Where(s => !_ignored.Contains(s.Name)).ToArray(); Bitmap[] images = new Bitmap[files.Length]; FileInfo[] icons = _iconsPath.GetFiles("*.png"); for (int i = 0; i < files.Length; i++) { FileInfo definition = files[i]; FileInfo icon = icons.FirstOrDefault(s => s.Name.Contains(Path.GetFileNameWithoutExtension(definition.Name))); if (icon == null) { continue; // found an icon } Image img = Image.FromFile(icon.FullName); images[i] = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppPArgb); using (Graphics g = Graphics.FromImage(images[i])) { g.PageUnit = GraphicsUnit.Pixel; g.InterpolationMode = InterpolationMode.NearestNeighbor; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.SmoothingMode = SmoothingMode.AntiAlias; g.DrawImage(img, 0, 0, img.Width, img.Height); } string setName = Path.GetFileNameWithoutExtension(definition.Name); BuildSet buildSet = new BuildSet(setName, images[i], !_smarts.Contains(setName)); bool istown = setName.ToLower() == "town"; using (StreamReader reader = new StreamReader(definition.OpenRead())) { while (!reader.EndOfStream) { string line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { continue; } string[] parts = line.Split('\t'); if (parts.Length >= 5) { bool enabled = parts[0] == "+"; string description = parts[1].TrimEnd().TrimStart(); Position position = Position.Parse(parts[2] + "." + parts[3]); int map = parts[4].ToInt(); BuildingEntry entry = new BuildingEntry(buildSet, description, position, map) { IsEnabled = enabled, IsTown = istown }; if (parts.Length >= 6) { entry.ShowName = parts[5] == "true"; } buildSet.Entries.Add(entry); } } } BuildSets.Add(buildSet); } // patch for towns BuildSet townSet = BuildSets.FirstOrDefault(s => s.Name.ToLower() == "town"); if (townSet != null) { BuildSets.Remove(townSet); BuildSets.Add(townSet); } // end patch // load houses FileInfo housesDef = _definitionsPath.GetFiles().FirstOrDefault(s => s.Name == _ignored[1]); if (housesDef != null) { using (StreamReader reader = new StreamReader(housesDef.FullName)) { while (!reader.EndOfStream) { string line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { continue; } string[] data = line.Split('\t'); if (data.Length <= 0 || data.Length < 5) { continue; } if (!ushort.TryParse(data[0], out ushort graphic)) { graphic = ushort.Parse(data[0], NumberStyles.HexNumber); } Position loc = Position.Parse(data[1] + "." + data[2]); Size size = new Size(data[3].ToInt(), data[4].ToInt()); int map = data[5].ToInt(); string descr = data[6]; HouseEntry house = new HouseEntry(descr, graphic, loc, size, map); Houses.Add(house); } } } else { new FileInfo(Path.Combine(_definitionsPath.FullName, _ignored[1])).Create().Close(); } // load guardlines FileInfo guardlinesDef = _definitionsPath.GetFiles().FirstOrDefault(s => s.Name == _ignored[0]); if (guardlinesDef != null) { using (StreamReader reader = new StreamReader(guardlinesDef.FullName)) { while (!reader.EndOfStream) { string line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { continue; } string[] data = line.Split('\t'); if (data.Length <= 0 || data.Length < 5) { continue; } if (data[0].StartsWith("#")) { continue; } Position loc = Position.Parse(data[0] + "." + data[1]); // ignore data[2] Size size = new Size(data[3].ToInt(), data[4].ToInt()); int map = data[5].ToInt(); GuardlineEntry guardline = new GuardlineEntry(loc, size, map); Guardlines.Add(guardline); } } } else { new FileInfo(Path.Combine(_definitionsPath.FullName, _ignored[0])).Create().Close(); } ParseUOAM(); }
public static bool ParseUOAM() { DirectoryInfo dir = new DirectoryInfo("Definitions"); FileInfo[] files = dir.GetFiles("*.map"); Regex regex = new Regex("^([\\+-])(.*):\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(.*)$"); foreach (FileInfo file in files) { using (StreamReader reader = new StreamReader(File.OpenRead(file.FullName))) { while (!reader.EndOfStream) { string line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { continue; } Match match = regex.Match(line); if (match.Success) { string type = match.Groups[2].ToString(); int x = match.Groups[3].ToString().ToInt(); int y = match.Groups[4].ToString().ToInt(); int map = match.Groups[5].ToString().ToInt(); string descr = match.Groups[6].ToString(); switch (type) { case "Minax's Fortress": case "point of interest": type = "POINT"; break; case "marble patio": type = "MARPATIO"; break; case "theater": type = "THEATRE"; break; case "teleporter": type = "TELEPORT"; break; } bool ok = true; foreach (BuildSet s in BuildSets) { if (s.Entries.FirstOrDefault(j => j.Location.X == x && j.Location.Y == y) != null) { ok = false; break; } } if (!ok) { continue; } BuildSet set = BuildSets.FirstOrDefault(s => s.Name.ToLower().Contains(type.Replace(" ", "").ToLower())); if (set != null) { set.Entries.Add(new BuildingEntry(set, descr, new Position((short)x, (short)y), map) { IsUOAM = true }); } } } } } return(true); }
public void GenRunes(Save save) { if (save?.Runes == null) return; if (!getRunningHandle()) return; try { if (Type == BuildType.Lock) { foreach (var r in Mon.Current.Runes) { if (r != null) { if (r.Locked) runes[r.Slot - 1] = new Rune[0]; else runes[r.Slot - 1] = new Rune[] { r }; } } return; } if (Type == BuildType.Link && LinkBuild == null) { for (int i = 0; i < 6; i++) runes[i] = new Rune[0]; return; } // todo: less .ToArray-ing ParallelQuery<Rune> rsGlobal = save.Runes.AsParallel(); // if not saving stats, cull unusable here if (!BuildSaveStats) { // Only using 'inventory' or runes on mon // also, include runes which have been unequipped (should only look above) if (!RunesUseEquipped || RunesOnlyFillEmpty) rsGlobal = rsGlobal.Where(r => r.IsUnassigned || r.AssignedId == Mon.Id || r.Swapped); // only if the rune isn't currently locked for another purpose if (!RunesUseLocked) rsGlobal = rsGlobal.Where(r => !r.Locked); rsGlobal = rsGlobal.Where(r => !BannedRuneId.Any(b => b == r.Id) && !BannedRunesTemp.Any(b => b == r.Id)); } if ((BuildSets.Any() || RequiredSets.Any()) && BuildSets.All(s => Rune.SetRequired(s) == 4) && RequiredSets.All(s => Rune.SetRequired(s) == 4)) { // if only include/req 4 sets, include all 2 sets autoRuneSelect && () rsGlobal = rsGlobal.Where(r => BuildSets.Contains(r.Set) || RequiredSets.Contains(r.Set) || Rune.SetRequired(r.Set) == 2); } else if (BuildSets.Any() || RequiredSets.Any()) { rsGlobal = rsGlobal.Where(r => BuildSets.Contains(r.Set) || RequiredSets.Contains(r.Set)); // Only runes which we've included } if (BuildSaveStats) { foreach (Rune r in rsGlobal) { r.manageStats.AddOrUpdate("currentBuildPoints", 0, (k, v) => 0); if (!BuildGoodRunes) r.manageStats.AddOrUpdate("Set", 1, (s, d) => { return d + 1; }); else r.manageStats.AddOrUpdate("Set", 0.001, (s, d) => { return d + 0.001; }); } } int?[] slotFakes = new int?[6]; bool[] slotPred = new bool[6]; getPrediction(slotFakes, slotPred); // Set up each runeslot for (int i = 0; i < 6; i++) { // put the right ones in runes[i] = rsGlobal.Where(r => r.Slot == i + 1).ToArray(); // makes sure that the primary stat type is in the selection if (i % 2 == 1 && SlotStats[i].Count > 0) // actually evens because off by 1 { runes[i] = runes[i].AsParallel().Where(r => SlotStats[i].Contains(r.Main.Type.ToForms())).ToArray(); } if (BuildSaveStats) { foreach (Rune r in runes[i]) { if (!BuildGoodRunes) r.manageStats.AddOrUpdate("TypeFilt", 1, (s, d) => { return d + 1; }); else r.manageStats.AddOrUpdate("TypeFilt", 0.001, (s, d) => { return d + 0.001; }); } // cull here instead if (!RunesUseEquipped || RunesOnlyFillEmpty) runes[i] = runes[i].AsParallel().Where(r => r.IsUnassigned || r.AssignedId == Mon.Id || r.Swapped).ToArray(); if (!RunesUseLocked) runes[i] = runes[i].AsParallel().Where(r => !r.Locked).ToArray(); } } // clean out runes which won't make complete sets cleanBroken(); // clean out runes which won't pass the minimum cleanMinimum(); if (AutoRuneSelect) { // TODO: triple pass: start at needed for min, but each pass reduce the requirements by the average of the chosen runes for that pass, increase it by build scoring var needed = NeededForMin(slotFakes, slotPred); if (needed == null) AutoRuneSelect = false; if (AutoRuneSelect) { var needRune = new Stats(needed) / 6; // Auto-Rune select picking N per RuneSet should be fine to pick more because early-out should keep times low. // reduce number of runes to 10-15 // odds first, then evens foreach (int i in new int[] { 0, 2, 4, 5, 3, 1 }) { Rune[] rr = new Rune[0]; foreach (var rs in RequiredSets) { rr = rr.Concat(runes[i].AsParallel().Where(r => r.Set == rs).OrderByDescending(r => runeVsStats(r, needRune) * 10 + runeVsStats(r, Sort)).Take(AutoRuneAmount / 2).ToArray()).ToArray(); } if (rr.Length < AutoRuneAmount) rr = rr.Concat(runes[i].AsParallel().Where(r => !rr.Contains(r)).OrderByDescending(r => runeVsStats(r, needRune) * 10 + runeVsStats(r, Sort)).Take(AutoRuneAmount - rr.Length).ToArray()).Distinct().ToArray(); runes[i] = rr; } cleanBroken(); } } if (!AutoRuneSelect) { // TODO: Remove #if BUILD_RUNE_LOGGING //var tmp = RuneLog.logTo; //using (var fs = new System.IO.FileStream("sampleselect.log", System.IO.FileMode.Create)) //using (var sw = new System.IO.StreamWriter(fs)) { RuneLog.logTo = sw; #else { #endif // Filter each runeslot for (int i = 0; i < 6; i++) { // default fail OR Predicate<Rune> slotTest = MakeRuneScoring(i + 1, slotFakes[i] ?? 0, slotPred[i]); runes[i] = runes[i].AsParallel().Where(r => slotTest.Invoke(r)).OrderByDescending(r => r.manageStats.GetOrAdd("testScore", 0)).ToArray(); var filt = LoadFilters(i + 1); if (filt.Count != null) { var tSets = RequiredSets.Count + BuildSets.Except(RequiredSets).Count(); var perc = RequiredSets.Count / (float)tSets; var reqLoad = Math.Max(2,(int)((filt.Count ?? AutoRuneAmount ) * perc)); var rr = runes[i].AsParallel().Where(r => RequiredSets.Contains(r.Set)).GroupBy(r => r.Set).SelectMany(r => r).Take(reqLoad).ToArray(); var incLoad = (filt.Count ?? AutoRuneAmount) - rr.Count(); runes[i] = rr.Concat(runes[i].AsParallel().Where(r => !RequiredSets.Contains(r.Set)).Take(incLoad)).ToArray(); // TODO: pick 20% per required set // Then fill remaining with the best from included // Go around checking if there are enough runes from each set to complete it (if NonBroken) // Check if removing N other runes of SCORE will permit finishing set // Remove rune add next best in slot } if (BuildSaveStats) { foreach (Rune r in runes[i]) { if (!BuildGoodRunes) r.manageStats.AddOrUpdate("RuneFilt", 1, (s, d) => d + 1); else r.manageStats.AddOrUpdate("RuneFilt", 0.001, (s, d) => d + 0.001); } } } } } if (RunesDropHalfSetStat) { for (int i = 0; i < 6; i++) { double rmm = 0; var runesForSlot = runes[i]; var outRunes = new List<Rune>(); var runesBySet = runesForSlot.GroupBy(r => r.Set); foreach (var rsg in runesBySet) { var runesByMain = rsg.GroupBy(r => r.Main.Type); foreach (var rmg in runesByMain) { rmm = rmg.Max(r => r.manageStats.GetOrAdd("testScore", 0)) * 0.6; if (rmm > 0) { outRunes.AddRange(rmg.Where(r => r.manageStats.GetOrAdd("testScore", 0) > rmm)); } } } if (rmm > 0) runes[i] = outRunes.ToArray(); } } // if we are only to fill empty slots if (RunesOnlyFillEmpty) { for (int i = 0; i < 6; i++) { if (Mon.Current.Runes[i] != null && (!Mon.Current.Runes[i]?.Locked ?? false)) { runes[i] = new Rune[0]; } } } // always try to put the current rune back in for (int i = 0; i < 6; i++) { var r = Mon.Current.Runes[i]; if (r == null) continue; bool isGoodType = true; if (i % 2 == 1 && SlotStats[i].Count > 0) { isGoodType = SlotStats[i].Contains(r.Main.Type.ToForms()); } if (!runes[i].Contains(r) && !r.Locked && isGoodType) { var tl = runes[i].ToList(); tl.Add(r); runes[i] = tl.ToArray(); } } grinds = runes.SelectMany(rg => rg.SelectMany(r => r.FilterGrinds(save.Crafts).Concat(r.FilterEnchants(save.Crafts)))).Distinct().ToArray(); } finally { IsRunning = false; } }