/// <summary> /// Gets the line representing the entry as a CSV row. /// </summary> /// <param name="entry">The entry to convert.</param> /// <returns>A Comma-Separated Values row containing the monster entry, as a string.</returns> private static string getLineFromEntry(BestiaryEntry entry) { StringBuilder sb = new StringBuilder(); // Join together the strings so they will be in one entry. string joinedActions = JoinStrings(entry.Actions); string joinedTraits = JoinStrings(entry.Traits); // Beast Size AC HP Speed Senses Str Mod Dex Mod Con Mod Int Mod Wis Mod Cha Mod Alignment Traits Actions Level XP object[] values = new object[] { entry.Name, entry.Size, entry.ArmorClass, entry.HitPoints, entry.Speed, entry.Senses, entry.Strength, null, entry.Dexterity, null, entry.Constitution, null, entry.Intelligence, null, entry.Wisdom, null, entry.Charisma, null, entry.Alignment, joinedTraits, joinedActions, entry.Level, entry.XP }; // Append all the values in csv format foreach (object value in values) { sb.Append(string.Format("{0}~", value)); } return sb.ToString(); }
/// <summary> /// Parses a creature from the entry text. /// </summary> /// <param name="text">The text.</param> /// <returns>The parsed creature, or null if an error occurred.</returns> public static BestiaryEntry CreateFromText(string text) { // Clean the whitespace from the entries, remove the carriage returns, and then split on newlines. // Ideally, this is make every string in lines a line of the text. text = text.Trim(); text.Replace("\r", ""); var lines = text.Split('\n'); // LINQ syntax. Select only the lines that have something and that don't contain " " lines = (from line in lines where !string.IsNullOrWhiteSpace(line) && !line.Contains(" ") select line.Trim()).ToArray(); var entry = new BestiaryEntry(); entry.Text = text; // Try parsing the entry. If fails, return null and log the error. try { entry.Name = lines[0]; entry.SizeType = lines[1]; entry.Size = entry.SizeType.Split().First(); entry.Type = entry.SizeType.Split().Last(); entry.ArmorClass = JoinStrings(lines[2].Split().Skip(2)); entry.HitPoints = lines[3].Split().Skip(2).First(); entry.Speed = lines[4].Split()[1]; entry.Senses = JoinStrings(lines[5].Split().Skip(1)); entry.Strength = lines[6].Split().Skip(1).First(); entry.Dexterity = lines[7].Split().Skip(1).First(); entry.Constitution = lines[8].Split().Skip(1).First(); entry.Intelligence = lines[9].Split().Skip(1).First(); entry.Wisdom = lines[10].Split().Skip(1).First(); entry.Charisma = lines[11].Split().Skip(1).First(); entry.Alignment = lines[12].Split().Skip(1).First(); entry.Languages = JoinStrings(lines[13].Split().Skip(1)); // LINQ Shenanigans. Get all the strings in between TRAITS and ACTION, making sure to stop before ENCOUNTER BUILDING. entry.Traits = (from line in lines.SkipWhile(x => x != "TRAITS").TakeWhile(x => x != "ACTIONS" && x != "ENCOUNTER BUILDING") select line).Skip(1).ToList(); // Get all strings between ACTIONS and ENCOUNTER BUILDING entry.Actions = (from line in lines.SkipWhile(x => x != "ACTIONS").TakeWhile(x => x != "ENCOUNTER BUILDING") select line).Skip(1).ToList(); // The last line should be the XP lines entry.XPLine = lines.Last(); int result; // Pull out the Level and XP as ints from the XPLine var xpResults = (from word in entry.XPLine.Split() where Int32.TryParse(word, out result) select Convert.ToInt32(word)); entry.Level = xpResults.First(); entry.XP = xpResults.Last(); } catch (Exception ex) { Console.WriteLine("Exception Caught in {0}: {1}", entry.Name, ex.Message); // Log the error using (StreamWriter logFile = File.AppendText(LOG_FILE_PATH)) { logFile.WriteLine(text); logFile.WriteLine(string.Format("========{0}========", errCount++)); } // Return null return null; } // Log the success and return the parsed creature. using (StreamWriter logFile = File.AppendText(LOG_FILE_PATH)) { logFile.WriteLine("{0} successfully parsed.", entry.Name); logFile.WriteLine(string.Format("========{0}========", errCount++)); } return entry; }