/// <summary> /// Tries to parse an item based on the text that Path of Exile gives on a Ctrl+C action. /// There is no recurring logic here so every case has to be handled manually. /// </summary> public static Item ParseItem(string text) { Item item = null; bool isIdentified, hasQuality, isCorrupted; try { var lines = text.Split(NEWLINE_SEPERATOR, StringSplitOptions.RemoveEmptyEntries); // Every item should start with Rarity in the first line. if (!lines[0].StartsWith("Rarity: ")) { throw new Exception("Probably not an item."); } // If the item is Unidentified, the second line will be its Type instead of the Name. isIdentified = !lines.Any(x => x == StringConstants.DescriptionUnidentified); hasQuality = lines.Any(x => x.Contains(StringConstants.DescriptionQuality)); isCorrupted = lines.Any(x => x == StringConstants.DescriptionCorrupted); var rarity = lines[0].Replace(StringConstants.DescriptionRarity, string.Empty); switch (rarity) { case StringConstants.RarityUnique: item = new EquippableItem(); if (isIdentified) { item.Name = lines[1]; item.Type = lines[2]; } else { item.Type = lines[1]; } var links = GetLinkCount(lines.Where(c => c.StartsWith(StringConstants.DescriptionSockets)).FirstOrDefault()); if (links >= 5) { ((EquippableItem)item).Links = new SocketFilterOption() { Min = links, Max = links, }; } ((EquippableItem)item).Rarity = rarity; break; case StringConstants.RarityRare: item = new EquippableItem() { Name = lines[2].Replace(StringConstants.PrefixSuperior, string.Empty), Type = lines[2].Replace(StringConstants.PrefixSuperior, string.Empty), ItemLevel = GetNumberFromString(lines.Where(c => c.StartsWith(StringConstants.DescriptionItemLevel)).FirstOrDefault()), Rarity = rarity, }; var links2 = GetLinkCount(lines.Where(c => c.StartsWith(StringConstants.DescriptionSockets)).FirstOrDefault()); // better naming if (links2 >= 5) { ((EquippableItem)item).Links = new SocketFilterOption() { Min = links2, Max = links2, }; } var influence = GetInfluenceType(lines.LastOrDefault()); ((EquippableItem)item).Influence = influence; break; case StringConstants.RarityMagic: throw new Exception("Magic items not supported for now."); case StringConstants.RarityNormal: if (lines.Any(c => c.StartsWith(StringConstants.DescriptionItemLevel))) // Equippable Item { item = new EquippableItem() { Type = lines[1].Replace(StringConstants.PrefixSuperior, string.Empty), ItemLevel = GetNumberFromString(lines.Where(c => c.StartsWith(StringConstants.DescriptionItemLevel)).FirstOrDefault()), Rarity = rarity, // TODO Non-Unique Rarity }; var influence2 = GetInfluenceType(lines.LastOrDefault()); // Better naming ((EquippableItem)item).Influence = influence2; var link3 = GetLinkCount(lines.Where(c => c.StartsWith(StringConstants.DescriptionSockets)).FirstOrDefault()); // Better naming if (link3 >= 5) { ((EquippableItem)item).Links = new SocketFilterOption() { Min = link3, Max = link3, }; } } else // Fragment { item = new FragmentItem() { Type = lines[1], }; } break; case StringConstants.RarityCurrency: item = new CurrencyItem() { Name = lines[1] }; break; case StringConstants.RarityGem: item = new GemItem() { Type = lines[1], // For Gems the Type has to be set to the Gem Name insead of the name itself Level = GetNumberFromString(lines[4]), Quality = hasQuality ? GetNumberFromString(lines.Where(x => x.StartsWith(StringConstants.DescriptionQuality)).FirstOrDefault()) : "0", // Quality Line Can move for different Gems }; break; case StringConstants.RarityDivinationCard: item = new CurrencyItem() { Name = lines[1], Type = lines[1], }; break; default: throw new NotImplementedException(); } } catch (Exception e) { Logger.Log("Could not parse item. " + e.Message); return(null); } item.IsCorrupted = isCorrupted ? "true" : "false"; return(item); }
/// <summary> /// Tries to parse an item based on the text that Path of Exile gives on a Ctrl+C action. /// There is no recurring logic here so every case has to be handled manually. /// </summary> public static Item ParseItem(string text) { Item item = null; bool isIdentified, hasQuality, isCorrupted; try { // Splitting Properties var properties = text.Split(PROPERTY_SEPERATOR, StringSplitOptions.RemoveEmptyEntries).ToList(); foreach (var prop in properties) { var lines = prop.Split(NEWLINE_SEPERATOR, StringSplitOptions.RemoveEmptyEntries); if (lines.FirstOrDefault().StartsWith(StringConstants.DescriptionRarity)) { item = new EquippableItem(); ((EquippableItem)item).Rarity = lines.FirstOrDefault().Replace(StringConstants.DescriptionRarity, string.Empty); item.Name = lines.Skip(1).FirstOrDefault(); item.Type = lines.LastOrDefault(); item.Type = item.Type == item.Name ? item.Type.Replace("Superior ", string.Empty) : item.Type; } else if (lines.FirstOrDefault().StartsWith(StringConstants.DescriptionRequirements)) { ((EquippableItem)item).Req = new ReqValue(); foreach (var line in lines) { if (line.StartsWith("Level: ")) { int.TryParse(line.Replace("Level: ", string.Empty), out int res); ((EquippableItem)item).Req.Level = res; } else if (line.StartsWith("Dex: ")) { int.TryParse(line.Replace("Dex: ", string.Empty), out int res); ((EquippableItem)item).Req.Dex = res; } else if (line.StartsWith("Str: ")) { int.TryParse(line.Replace("Str: ", string.Empty), out int res); ((EquippableItem)item).Req.Str = res; } else if (line.StartsWith("Int: ")) { int.TryParse(line.Replace("Int: ", string.Empty), out int res); ((EquippableItem)item).Req.Int = res; } } } else if (lines.FirstOrDefault().StartsWith(StringConstants.DescriptionSockets)) { var socklinks = lines.FirstOrDefault().Replace(StringConstants.DescriptionSockets, string.Empty); ((EquippableItem)item).Socket = new SocketValue { R = socklinks.Count(x => x == 'R'), G = socklinks.Count(x => x == 'G'), B = socklinks.Count(x => x == 'B'), W = socklinks.Count(x => x == 'W') }; ((EquippableItem)item).Socket.Sockets = ((EquippableItem)item).Socket.R + ((EquippableItem)item).Socket.G + ((EquippableItem)item).Socket.B + ((EquippableItem)item).Socket.W; ((EquippableItem)item).Socket.Links = Regex.Replace(socklinks, @"[RGBW]", string.Empty).Split(' ').MaxBy(x => x.Length).FirstOrDefault().Length + 1; } else if (lines.FirstOrDefault().StartsWith(StringConstants.DescriptionItemLevel)) { int.TryParse(lines.FirstOrDefault().Replace(StringConstants.DescriptionItemLevel, string.Empty), out int res); ((EquippableItem)item).ItemLevel = res; } else if (lines.FirstOrDefault().StartsWith(StringConstants.DescriptionQuality) || lines.FirstOrDefault().StartsWith(StringConstants.DescriptionArmour) || lines.FirstOrDefault().StartsWith(StringConstants.DescriptionEvasion) || lines.FirstOrDefault().StartsWith(StringConstants.DescriptionEnergyShield) || lines.FirstOrDefault().StartsWith(StringConstants.DescriptionBlock)) { ((EquippableItem)item).Armour = new ArmourValue(); foreach (var line in lines) { var match = Regex.Match(line, @"[\d]+"); int number = 0; if (match.Success) { int.TryParse(match.Value, out number); } if (line.StartsWith("Quality: ")) { ((EquippableItem)item).Armour.Quality = number; } else if (line.StartsWith("Armour: ")) { ((EquippableItem)item).Armour.Armour = number; } else if (line.StartsWith("Evasion: ")) { ((EquippableItem)item).Armour.Evasion = number; } else if (line.StartsWith("Energy Shield: ")) { ((EquippableItem)item).Armour.EnergyShield = number; } else if (line.StartsWith("Block: ")) { ((EquippableItem)item).Armour.Block = number; } } } else if (lines.FirstOrDefault().StartsWith(StringConstants.DescriptionMapTier)) { int.TryParse(lines.FirstOrDefault().Replace(StringConstants.DescriptionMapTier, string.Empty), out int tier); ((EquippableItem)item).MapTier = tier; } else if (lines.FirstOrDefault().EndsWith(" Item")) { Enum.TryParse(lines.FirstOrDefault().Replace(" Item", string.Empty), out InfluenceType result); ((EquippableItem)item).Influence = result; } else if (lines.Any(x => x == "Unidentified")) { //item.IsIdentified = true; } else { foreach (var line in lines) { var search = Regex.Replace(line, @"([\+\-\d.]+)", "#"); if (search.EndsWith(" (implicit)")) { search = search.Replace(" (implicit)", string.Empty); //To Do relace The Elder,... with # var category = TradeClient.AttributeCategories.FirstOrDefault(x => x.Label.Contains("Implicit")); var res = category?.Entries.FirstOrDefault(x => x.Text == search); if (res != null) { ((EquippableItem)item).Stats.Add(res); } } else if (search.EndsWith(" (crafted)")) { search = search.Replace(" (crafted)", string.Empty); var category = TradeClient.AttributeCategories.FirstOrDefault(x => x.Label.Contains("Crafted")); var res = category?.Entries.FirstOrDefault(x => x.Text == search); if (res != null) { ((EquippableItem)item).Stats.Add(res); } } else if (search.EndsWith(" (fractured)")) { search = search.Replace(" (fractured)", string.Empty); var category = TradeClient.AttributeCategories.FirstOrDefault(x => x.Label.Contains("Fractured")); var res = category?.Entries.FirstOrDefault(x => x.Text == search); if (res != null) { ((EquippableItem)item).Stats.Add(res); } } else if (search.EndsWith(" (veiled)")) { search = search.Replace(" (veiled)", string.Empty); var category = TradeClient.AttributeCategories.FirstOrDefault(x => x.Label.Contains("Veiled")); var res = category?.Entries.FirstOrDefault(x => x.Text == search); if (res != null) { ((EquippableItem)item).Stats.Add(res); } } else if (search.EndsWith(" (delve)")) { search = search.Replace(" (delve)", string.Empty); var category = TradeClient.AttributeCategories.FirstOrDefault(x => x.Label.Contains("Delve")); var res = category?.Entries.FirstOrDefault(x => x.Text == search); if (res != null) { ((EquippableItem)item).Stats.Add(res); } } else { //Find Properties foreach (var cat in TradeClient.AttributeCategories.Where(x => x.Label == "Pseudo" || x.Label == "Explicit" || x.Label == "Enchant" || x.Label == "Monster")) { //StartsWith for (local) var res = cat.Entries.FirstOrDefault(x => x.Text.StartsWith(search)); if (res != null) { ((EquippableItem)item).Stats.Add(res); } } } } } } } catch (Exception e) { Logger.Log("Could not parse item. " + e.Message); return(null); } return(item); }
/// <summary> /// Tries to parse an item based on the text that Path of Exile gives on a Ctrl+C action. /// There is no recurring logic here so every case has to be handled manually. /// </summary> public static Item ParseItem(string text) { Item item = null; bool isIdentified, hasQuality, isCorrupted, isMap, isBlighted, hasNote; try { var lines = text.Split(NEWLINE_SEPERATOR, StringSplitOptions.RemoveEmptyEntries); // Every item should start with Rarity in the first line. if (!lines[0].StartsWith(LanguageSettings.Provider.DescriptionRarity)) { throw new Exception("Probably not an item."); } // If the item is Unidentified, the second line will be its Type instead of the Name. isIdentified = !lines.Any(x => x == LanguageSettings.Provider.DescriptionUnidentified); hasQuality = lines.Any(x => x.Contains(LanguageSettings.Provider.DescriptionQuality)); isCorrupted = lines.Any(x => x == LanguageSettings.Provider.DescriptionCorrupted); isMap = lines.Any(x => x.Contains(LanguageSettings.Provider.DescriptionMapTier)); isBlighted = lines.Any(x => x.Contains(LanguageSettings.Provider.PrefixBlighted)); hasNote = lines.LastOrDefault().Contains("Note"); var rarity = lines[0].Replace(LanguageSettings.Provider.DescriptionRarity, string.Empty); if (isMap) { item = new MapItem() { ItemQuantity = GetNumberFromString(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionItemQuantity)).FirstOrDefault()), ItemRarity = GetNumberFromString(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionItemRarity)).FirstOrDefault()), MonsterPackSize = GetNumberFromString(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionMonsterPackSize)).FirstOrDefault()), MapTier = GetNumberFromString(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionMapTier)).FirstOrDefault()), Rarity = rarity, }; if (rarity == LanguageSettings.Provider.RarityNormal) { item.Name = lines[1].Replace(LanguageSettings.Provider.PrefixSuperior, string.Empty).Trim(); item.Type = lines[1].Replace(LanguageSettings.Provider.PrefixSuperior, string.Empty).Replace(LanguageSettings.Provider.PrefixBlighted, string.Empty).Trim(); } else if (rarity == LanguageSettings.Provider.RarityMagic) // Extract only map name { item.Name = LanguageSettings.Provider.PrefixBlighted + " " + TradeClient.MapNames.Where(c => lines[1].Contains(c)).FirstOrDefault(); item.Type = TradeClient.MapNames.Where(c => lines[1].Contains(c)).FirstOrDefault(); // Search map name from statics } else if (rarity == LanguageSettings.Provider.RarityRare) { item.Name = lines[2].Trim(); item.Type = lines[2].Replace(LanguageSettings.Provider.PrefixBlighted, string.Empty).Trim(); } else if (rarity == LanguageSettings.Provider.RarityUnique) { if (!isIdentified) { item.Name = lines[1].Replace(LanguageSettings.Provider.PrefixSuperior, string.Empty).Trim(); } else { item.Name = lines[1]; } } ((MapItem)item).IsBlight = isBlighted ? "true" : "false"; } else if (rarity == LanguageSettings.Provider.RarityUnique) { item = new EquippableItem { Name = lines[1], Type = isIdentified ? lines[2] : lines[1] }; var links = GetLinkCount(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionSockets)).FirstOrDefault()); if (links >= 5) { ((EquippableItem)item).Links = new SocketFilterOption() { Min = links, Max = links, }; } } else if (rarity == LanguageSettings.Provider.RarityRare) { item = new EquippableItem() { Name = lines[1], Type = lines[2], ItemLevel = GetNumberFromString(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionItemLevel)).FirstOrDefault()), }; var links = GetLinkCount(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionSockets)).FirstOrDefault()); if (links >= 5) { ((EquippableItem)item).Links = new SocketFilterOption() { Min = links, Max = links, }; } if (hasNote) { ((EquippableItem)item).Influence = GetInfluenceType(lines[lines.Length - 3]); } else { ((EquippableItem)item).Influence = GetInfluenceType(lines.LastOrDefault()); } } else if (rarity == LanguageSettings.Provider.RarityMagic) { throw new Exception("Magic items are not yet supported."); } else if (rarity == LanguageSettings.Provider.RarityNormal) { if (lines.Any(c => c.StartsWith(LanguageSettings.Provider.DescriptionItemLevel))) // Equippable Item { item = new EquippableItem() { Type = lines[1].Replace(LanguageSettings.Provider.PrefixSuperior, string.Empty).Trim(), Name = lines[1].Replace(LanguageSettings.Provider.PrefixSuperior, string.Empty).Trim(), ItemLevel = GetNumberFromString(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionItemLevel)).FirstOrDefault()), }; if (hasNote) { ((EquippableItem)item).Influence = GetInfluenceType(lines[lines.Length - 3]); } else { ((EquippableItem)item).Influence = GetInfluenceType(lines.LastOrDefault()); } var links = GetLinkCount(lines.Where(c => c.StartsWith(LanguageSettings.Provider.DescriptionSockets)).FirstOrDefault()); if (links >= 5) { ((EquippableItem)item).Links = new SocketFilterOption() { Min = links, Max = links, }; } } else if (lines.Any(c => c.Contains(LanguageSettings.Provider.KeywordProphecy))) // Prophecy { item = new ProphecyItem() { Name = lines[1], Type = lines[1], }; } else // Fragment { item = new FragmentItem() { Name = lines[1], Type = lines[1], }; } } else if (rarity == LanguageSettings.Provider.RarityCurrency) { item = new CurrencyItem() { Name = lines[1], Type = lines[1] }; } else if (rarity == LanguageSettings.Provider.RarityGem) { item = new GemItem() { Name = lines[1], // Need adjustment for Thai Language Type = lines[1], // For Gems the Type has to be set to the Gem Name insead of the name itself Level = GetNumberFromString(lines[4]), ExperiencePercent = lines.Any(x => x.StartsWith(LanguageSettings.Provider.DescriptionExperience)) ? ParseGemExperiencePercent(lines.Where(y => y.StartsWith(LanguageSettings.Provider.DescriptionExperience)).FirstOrDefault()) : 0, // Some gems have no experience like portal or max ranks Quality = hasQuality ? GetNumberFromString(lines.Where(x => x.StartsWith(LanguageSettings.Provider.DescriptionQuality)).FirstOrDefault()) : "0", // Quality Line Can move for different Gems IsVaalVersion = isCorrupted && lines[3].Contains(LanguageSettings.Provider.KeywordVaal) // check if the gem tags contain Vaal }; // if it's the vaal version, remap to have that name instead // Unsure if this works on non arabic lettering (ru/th/kr) if ((item as GemItem).IsVaalVersion) { string vaalName = lines.Where(x => x.Contains(LanguageSettings.Provider.KeywordVaal) && x.Contains(item.Name)).FirstOrDefault(); // this should capture the vaaled name version item.Name = vaalName; item.Type = vaalName; } } else if (rarity == LanguageSettings.Provider.RarityDivinationCard) { item = new DivinationCardItem() { Name = lines[1], Type = lines[1], }; } else { throw new NotImplementedException(); } if (item != null && string.IsNullOrEmpty(item.Rarity)) { item.Rarity = string.IsNullOrEmpty(rarity) ? "unknown" : rarity; } } catch (Exception e) { Logger.Log("Could not parse item. " + e.Message); return(null); } item.IsCorrupted = isCorrupted ? "true" : "false"; return(item); }