private Item parseWikiItem(WikiItemData wikiItem) { var item = new Item(); item.ItemName = wikiItem.Name.Trim(); item.IconFileName = wikiItem.IconFileName?.Trim(); foreach (string statLine in wikiItem.Stats) { try { parseStatLine(wikiItem, item, statLine); } catch (UnknownStatTokenException) { // add any unparseable lines as InfoText item.Info.Add(new ItemInfoLine() { ItemName = item.ItemName, Item = item, Text = statLine }); } } return(item); }
private void parseStatLine(WikiItemData wikiItem, Item item, string statLine) { var lineChunks = statLine .Replace(")(", ") (") // make life easier when parsing Effect corner cases .Split(' ', StringSplitOptions.RemoveEmptyEntries) .Select(chunk => chunk.Trim()) .Where(chunk => chunk != ":" && chunk != "+") .ToArray(); string firstChunk = cleanChunk(lineChunks[0]); string secondChunk = (lineChunks.Length == 1 ? null : cleanChunk(lineChunks[1])); // first check for tokens that we know will take up an entire line if (firstChunk == "AC") { if (item.ArmorClass != null) { throw new Exception("Multiple AC lines found for " + wikiItem.ToString()); } item.ArmorClass = Int32.Parse(secondChunk); } else if (firstChunk == "DMG") { if (item.AttackDamage != null) { throw new Exception("Multiple DMG lines found for " + wikiItem.ToString()); } item.AttackDamage = Int32.Parse(secondChunk); } else if (firstChunk == "SKILL" && secondChunk != "MOD") { if (item.WeaponSkillCode != null) { throw new Exception("Multiple Skill lines found for " + wikiItem.ToString()); } parseWeaponSkillLine(lineChunks, item); } else if (firstChunk == "SLOT" && secondChunk != "1") { if (item.Slots.Count > 0) { throw new Exception("Multiple Slot lines found for " + wikiItem.ToString()); } parseSlotsLine(lineChunks, item); } else if (firstChunk == "CLASS") { if (item.Classes.Count > 0) { throw new Exception("Multiple Class lines found for " + wikiItem.ToString()); } parseClassLine(lineChunks, item); } else if (firstChunk == "RACE") { if (item.Races.Count > 0) { throw new Exception("Multiple Race lines found for " + wikiItem.ToString()); } parseRaceLine(lineChunks, item); } else if (firstChunk == "DEITY" || firstChunk == "DIETY") { if (item.Deities.Count > 0) { throw new Exception("Multiple Deity lines found for " + wikiItem.ToString()); } parseDeityLine(lineChunks, item); } else if (firstChunk == "EFFECT") { if (item.EffectSpellName != null) { throw new Exception("Multiple Effect values found for " + wikiItem.ToString()); } parseEffectLine(lineChunks, item); } else if (firstChunk == "REQUIRED") { if (item.RequiredLevel != null) { throw new Exception("Multiple Required Level values for " + wikiItem.ToString()); } item.RequiredLevel = Int32.Parse(lineChunks.Last().TrimEnd('.')); } else if (firstChunk == "SINGING") { if (item.SingingModifier != null) { throw new Exception("Multiple Singing lines found for " + wikiItem.ToString()); } if (lineChunks.Length < 3) { item.SingingModifier = 0; } else { item.SingingModifier = Convert.ToInt32(cleanChunk(lineChunks[2])); } } else if (firstChunk == "PERCUSSION") { if (item.PercussionModifier != null) { throw new Exception("Multiple Percussion lines found for " + wikiItem.ToString()); } if (lineChunks.Length < 3) { item.PercussionModifier = 0; } else { item.PercussionModifier = Convert.ToInt32(cleanChunk(lineChunks[2])); } } else if (firstChunk == "STRINGED") { if (item.StringedModifier != null) { throw new Exception("Multiple Stringed lines found for " + wikiItem.ToString()); } if (lineChunks.Length < 3) { item.StringedModifier = 0; } else { item.StringedModifier = Convert.ToInt32(cleanChunk(lineChunks[2])); } } else if (firstChunk == "BRASS") { if (item.BrassModifier != null) { throw new Exception("Multiple Brass lines found for " + wikiItem.ToString()); } if (lineChunks.Length < 3) { item.BrassModifier = 0; } else { item.BrassModifier = Convert.ToInt32(cleanChunk(lineChunks[2])); } } else if (firstChunk == "WIND") { if (item.WindModifier != null) { throw new Exception("Multiple Wind lines found for " + wikiItem.ToString()); } if (lineChunks.Length < 3) { item.WindModifier = 0; } else { item.WindModifier = Convert.ToInt32(cleanChunk(lineChunks[2])); } } else { // it wasn't a whole-line token, so next check for tokens that can share a line int currentIndex = 0; while (currentIndex < lineChunks.Length) { string currentChunk = cleanChunk(lineChunks[currentIndex]); bool isChunkHandled = false; if (currentChunk == "NODROP") { item.IsNoDrop = true; isChunkHandled = true; } else if (currentChunk == "TEMPORARY" || currentChunk == "NORENT") { item.IsTemporary = true; isChunkHandled = true; } else if (currentChunk == "EXPENDABLE") { item.IsExpendable = true; isChunkHandled = true; } else if (currentChunk == "ARTIFACT") { item.IsArtifact = true; isChunkHandled = true; } else if (currentChunk == "WT") { if (item.Weight != 0) { throw new Exception("Multiple WT values found for " + wikiItem.ToString()); } currentIndex++; string nextChunk = cleanChunk(lineChunks[currentIndex]); item.Weight = float.Parse(nextChunk); isChunkHandled = true; } else if (currentChunk == "SIZE") { currentIndex++; string nextChunk = cleanChunk(lineChunks[currentIndex]); if (nextChunk == "CAPACITY") { currentIndex++; var nextNextChunk = cleanChunk(lineChunks[currentIndex]); if (item.CapacitySizeCode != null) { throw new Exception("Multiple Size Capacity values found for " + wikiItem.ToString()); } item.CapacitySizeCode = SizeCodes.All.Where(code => code.Equals(nextNextChunk, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); if (String.IsNullOrWhiteSpace(item.CapacitySizeCode)) { throw new Exception("Unrecognized Size Capacity" + nextNextChunk); } } else { if (item.SizeCode != null) { throw new Exception("Multiple Size values found for " + wikiItem.ToString()); } item.SizeCode = SizeCodes.All.Where(code => code.Equals(nextChunk, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); if (String.IsNullOrWhiteSpace(item.SizeCode)) { throw new Exception("Unrecognized Size " + nextChunk); } } isChunkHandled = true; } else if (currentChunk == "CAPACITY") { if (item.Capacity != null) { throw new Exception("Multiple Capacity values for " + wikiItem.ToString()); } currentIndex++; item.Capacity = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "RANGE") { if (item.Range != null) { throw new Exception("Multiple Range values found for " + wikiItem.ToString()); } currentIndex++; string rangeString = cleanChunk(lineChunks[currentIndex]); if (rangeString.Contains('/') || (lineChunks.Length > currentIndex + 1 && lineChunks[currentIndex + 1].Contains('/'))) { // there are multiple possible ranges (i.e. crafted arrows), so just set Range = null item.Range = null; while (cleanChunk(lineChunks[currentIndex + 1]) != "SIZE") { currentIndex++; } } else { item.Range = Int32.Parse(rangeString); } isChunkHandled = true; } else if (currentChunk == "HASTE") { if (item.Haste != null) { throw new Exception("Multiple Haste lines found for " + wikiItem.ToString()); } currentIndex++; item.Haste = float.Parse("0." + cleanChunk(lineChunks[currentIndex]).TrimStart('+').TrimEnd('%')); isChunkHandled = true; } else if (currentChunk == "STR") { if (item.Strength != null) { throw new Exception("Multiple STR values for " + wikiItem.ToString()); } currentIndex++; item.Strength = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "STA") { if (item.Stamina != null) { throw new Exception("Multiple STA values for " + wikiItem.ToString()); } currentIndex++; item.Stamina = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "AGI") { if (item.Agility != null) { throw new Exception("Multiple AGI values for " + wikiItem.ToString()); } currentIndex++; item.Agility = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "DEX") { if (item.Dexterity != null) { throw new Exception("Multiple DEX values for " + wikiItem.ToString()); } currentIndex++; item.Dexterity = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "WIS") { if (item.Wisdom != null) { throw new Exception("Multiple WIS values for " + wikiItem.ToString()); } currentIndex++; item.Wisdom = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "INT") { if (item.Intelligence != null) { throw new Exception("Multiple INT values for " + wikiItem.ToString()); } currentIndex++; item.Intelligence = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "CHA") { if (item.Charisma != null) { throw new Exception("Multiple CHA values for " + wikiItem.ToString()); } currentIndex++; item.Charisma = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentChunk == "HP") { currentIndex++; var nextChunk = cleanChunk(lineChunks[currentIndex]); int hpValue; if (Int32.TryParse(nextChunk, out hpValue)) { if (item.HitPoints != null) { throw new Exception("Multiple HP values for " + wikiItem.ToString()); } item.HitPoints = hpValue; isChunkHandled = true; } } else if (currentChunk == "MANA") { currentIndex++; string nextChunk = cleanChunk(lineChunks[currentIndex]); int manaValue; if (Int32.TryParse(nextChunk, out manaValue)) { if (item.Mana != null) { throw new Exception("Multiple MANA values for " + wikiItem.ToString()); } item.Mana = manaValue; isChunkHandled = true; } } else if (currentChunk == "AC") { if (item.ArmorClass != null) { throw new Exception("Multiple AC values for " + wikiItem.ToString()); } currentIndex++; item.ArmorClass = Int32.Parse(cleanChunk(lineChunks[currentIndex])); isChunkHandled = true; } else if (currentIndex + 1 < lineChunks.Length) { // this is NOT the last token in the line, so check for two-token combos string nextChunk = cleanChunk(lineChunks[currentIndex + 1]); // for stats that are two tokens ("SV MAGIC", "SV POISON", etc) if (currentChunk == "SV") { currentIndex += 2; int value = Int32.Parse(cleanChunk(lineChunks[currentIndex])); if (nextChunk == "MAGIC") { if (item.MagicResist != null) { throw new Exception("Multiple SV MAGIC values found for " + wikiItem.ToString()); } item.MagicResist = value; } else if (nextChunk == "POISON") { if (item.PoisonResist != null) { throw new Exception("Multiple SV POISON values found for " + wikiItem.ToString()); } item.PoisonResist = value; } else if (nextChunk == "DISEASE") { if (item.DiseaseResist != null) { throw new Exception("Multiple SV DISEASE values found for " + wikiItem.ToString()); } item.DiseaseResist = value; } else if (nextChunk == "FIRE") { if (item.FireResist != null) { throw new Exception("Multiple SV FIRE values found for " + wikiItem.ToString()); } item.FireResist = value; } else if (nextChunk == "COLD") { if (item.ColdResist != null) { throw new Exception("Multiple SV COLD values found for " + wikiItem.ToString()); } item.ColdResist = value; } else { throw new Exception("Unrecognized resist SV " + nextChunk); } isChunkHandled = true; } else if (currentChunk == "MAGIC" && nextChunk == "ITEM") { item.IsMagic = true; currentIndex++; isChunkHandled = true; } else if (currentChunk == "LORE" && nextChunk == "ITEM") { item.IsLore = true; currentIndex++; isChunkHandled = true; } else if (currentChunk == "QUEST" && nextChunk == "ITEM") { item.IsQuestItem = true; currentIndex++; isChunkHandled = true; } else if (currentChunk == "NO" && nextChunk == "DROP") { item.IsNoDrop = true; currentIndex++; isChunkHandled = true; } else if (currentChunk == "NO" && nextChunk == "RENT") { item.IsTemporary = true; currentIndex++; isChunkHandled = true; } else if (currentChunk == "NO" && nextChunk == "TRADE") { item.IsNoTrade = true; currentIndex++; isChunkHandled = true; } else if (currentChunk == "WEIGHT" && nextChunk == "REDUCTION") { if (item.WeightReduction != null) { throw new Exception("Multiple Weight Reduction values found for " + wikiItem.ToString()); } isChunkHandled = true; currentIndex += 2; var nextNextChunk = cleanChunk(lineChunks[currentIndex]); item.WeightReduction = float.Parse("0." + nextNextChunk.TrimEnd('%')); } else if (currentChunk == "CHARGES") { if (item.MaxCharges != null) { throw new Exception("Multiple Charges values found for " + wikiItem.ToString()); } currentIndex++; isChunkHandled = true; if (nextChunk == "UNLIMITED") { item.MaxCharges = null; } else { item.MaxCharges = Int32.Parse(nextChunk); } } } if (!isChunkHandled) { throw new UnknownStatTokenException(currentChunk); } currentIndex++; } // end while (currentIndex < lineChunks.Length) } // end else }