public List <PowerEntry>?Parse() { Regex r; Regex rs; Match m; Match ms; string cnt; int i; var p = new RawPowerData { Valid = false }; var powerSlots = new List <RawEnhData>(); var e = new RawEnhData(); var listPowers = new List <PowerEntry>(); try { cnt = File.ReadAllText(BuildString); } catch (Exception ex) { MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace); return(null); } cnt = Regex.Replace(cnt, @"[\r\n]", "\r\n"); // Line conversion to PC/Win format (just in case) cnt = Regex.Replace(cnt, @"\<br \/\>", string.Empty); // For good ol' Mids 1.962 support cnt = Regex.Replace(cnt, @"\ \;", " "); // Nbsp html entities to spaces cnt = Regex.Replace(cnt, @" {2,}", "\t"); // Note: [JS] Use of \s here break newlines // Compact a little those modern builds cnt = Regex.Replace(cnt, @"\t{2,}", "\t"); cnt = Regex.Replace(cnt, @"(\r\n){2,}", "\r\n"); // Alignment, builder software and version // Note: old Pine Hero Designer is listed as 'Hero Hero Designer' // Extended: Rogue/Vigilante will be added in a later release. r = new Regex(@"(Hero|Villain|Rogue|Vigilante) Plan by ([a-zA-Z\:\'\s]+) ([0-9\.]+)"); m = r.Match(cnt); if (!m.Success) { _ = MessageBox.Show( "This build cannot be recovered because it doesn't contain a valid plain text part.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return(null); } CharacterInfo.Alignment = m.Groups[1].Value; BuilderApp.Software = m.Groups[2].Value; BuilderApp.Version = m.Groups[3].Value; // Character name, level, origin and archetype r = new Regex(@"([^\r\n\t]+)\: Level ([0-9]{1,2}) ([a-zA-Z]+) ([a-zA-Z ]+)"); m = r.Match(cnt); if (!m.Success) { // Name is empty rs = new Regex(@"Level ([0-9]{1,2}) ([a-zA-Z]+) ([a-zA-Z ]+)"); ms = rs.Match(cnt); CharacterInfo.Name = string.Empty; CharacterInfo.Level = Convert.ToInt32(ms.Groups[1].Value, null); CharacterInfo.Origin = ms.Groups[2].Value; CharacterInfo.Archetype = ms.Groups[3].Value; } else { CharacterInfo.Name = m.Groups[1].Value; CharacterInfo.Level = Convert.ToInt32(m.Groups[2].Value, null); CharacterInfo.Origin = m.Groups[3].Value; CharacterInfo.Archetype = m.Groups[4].Value; } SetCharacterInfo(); // Main powersets r = new Regex(@"(Primary|Secondary) Power Set\: ([^\r\n\t]+)"); m = r.Match(cnt); while (m.Success) { PowerSets.Add(m.Groups[2].Value); m = m.NextMatch(); } // Pools and Ancillary/Epic powersets r = new Regex(@"(Power|Ancillary) Pool\: ([^\r\n\t]+)"); m = r.Match(cnt); while (m.Success) { if (m.Groups[2].Value != "Fitness") { PowerSets.Add(m.Groups[2].Value); } m = m.NextMatch(); } // Powers string PSlotsStr; string[] PSlots; string[] s; string? sContentEnh; r = new Regex(@"Level ([0-9]{1,2})\:\t([^\t]+)\t([^\r\n\t]+)"); m = r.Match(cnt); while (m.Success) { p = new RawPowerData(); e = new RawEnhData(); p.Slots = new List <RawEnhData>(); p.DisplayName = m.Groups[2].Value.Trim(); p.Level = Convert.ToInt32(m.Groups[1].Value, null); p.pData = DatabaseAPI.GetPowerByDisplayName(p.DisplayName, DatabaseAPI.GetArchetypeByName(CharacterInfo.Archetype).Idx); p.Powerset = p.pData != null?DatabaseAPI.GetPowersetByIndex(p.pData.PowerSetIndex) : null; p.Valid = CheckValid(p.pData); PSlotsStr = m.Groups.Count > 3 ? m.Groups[3].Value.Trim() : string.Empty; if (!string.IsNullOrEmpty(PSlotsStr)) { // Extract enhancement name and slot level ('A' for power inherent slot) // Handle special enhancements with parenthesis like ExpRnf-+Res(Pets)(50) PSlotsStr = Regex.Replace(PSlotsStr, @"\(([^A0-9]+)\)", "[$1]"); PSlots = Regex.Split(PSlotsStr, @",\s"); for (i = 0; i < PSlots.Length; i++) { s = Regex.Split(PSlots[i], @"/[\(\)]"); s = Array.FindAll(s, e => !string.IsNullOrWhiteSpace(e)); sContentEnh = s[0] == "Empty" ? null : ShortNamesConversion(s[0]); // Enhancement name (Enhancement.ShortName) try { e.InternalName = s[0]; e.Level = s[1] == "A" ? 0 : Convert.ToInt32(s[1], null); // Slot level ("A" is the auto-granted one) e.Boosters = 0; // Not handled e.HasCatalyst = false; e.eData = DatabaseAPI.GetEnhancementByUIDName(e.InternalName); p.Slots.Add(e); } catch (FormatException) // if (isNaN(s[1] { e.InternalName = "Empty"; e.Level = 0; e.Boosters = 0; e.HasCatalyst = false; e.eData = -1; p.Slots.Add(e); } } } if (p.Valid) { if (CheckValid(p.Powerset)) { PowerSets.Add(p.Powerset.FullName); } AddPowerToBuildSheet(p, ref listPowers); } } return(listPowers); }