public static void PrintIndex(BdatStringCollection bdats, string htmlDir) { var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine("<title>Xenoblade 2 BDAT Index</title>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); var grouped = bdats.Tables.Values.GroupBy(x => x.Filename).OrderBy(x => x.Key ?? "zzz"); foreach (var group in grouped) { sb.AppendLine($"<h2>{group.Key ?? "Other"}</h2>"); var subDir = Path.Combine("bdat", group.Key ?? string.Empty); foreach (var table in group.OrderBy(x => x.Name)) { var path = Path.Combine(subDir, table.Name) + ".html"; sb.AppendLine($"<a href=\"{path}\">{table.Name}</a><br/>"); } } sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); var filename = Path.Combine(htmlDir, "index.html"); File.WriteAllText(filename, sb.ToString()); }
public static void PrintBdatIndex(BdatStringCollection bdats, string htmlDir) { var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); string name = bdats.Game == Game.XB2 ? "2" : "X"; sb.AppendLine($"<title>Xenoblade {name} Data Tables</title>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); IOrderedEnumerable <IGrouping <string, BdatStringTable> > grouped = bdats.Tables.Values.GroupBy(x => x.Filename).OrderBy(x => x.Key ?? "zzz"); foreach (IGrouping <string, BdatStringTable> group in grouped) { sb.AppendLine($"<h2>{group.Key ?? "Other"}</h2>"); string subDir = group.Key ?? string.Empty; foreach (BdatStringTable table in group.OrderBy(x => x.Name)) { string path = Path.Combine(subDir, table.Name) + ".html"; sb.AppendLine($"<a href=\"{path}\">{table.Name}</a><br/>"); } } sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); string filename = Path.Combine(htmlDir, "index.html"); File.WriteAllText(filename, sb.ToString()); }
public static void GenerateClass(SaveType type, Indenter sb) { sb.AppendLine($"public partial class {type.Name}"); sb.AppendLineAndIncrease("{"); foreach (var field in type.Fields) { switch (field.Type) { case "Scalar": sb.AppendLine($"public {field.DataType} {field.Name} {{ get; set; }}"); break; case "Array": sb.AppendLine($"public {field.DataType}[] {field.Name} {{ get; set; }} = new {field.DataType}[{field.Length}];"); break; case "Bitfield": foreach (var value in field.Bitfield) { sb.AppendLine($"public {field.DataType} {value.Name} {{ get; set; }}"); } break; case "BitfieldArray": sb.AppendLine($"public byte[] {field.Name} {{ get; set; }} = new byte[{field.Length}];"); break; } } CreateReadFunction(type, sb); CreateWriteFunction(type, sb); sb.DecreaseAndAppendLine("}"); }
public static string Print(BdatCollection tables) { var sb = new Indenter(); BdatTable <FLD_SalvagePointList> pointList = tables.FLD_SalvagePointList; sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine("<title>Xenoblade 2 Salvaging Points</title>"); sb.AppendLine("<style>.tbox td{vertical-align: top;} table.BtnChallenge td,th{border: 1px solid;}table{margin:0;padding:0;border-collapse: collapse;}</style>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); foreach (FLD_SalvagePointList point in pointList.Where(x => x.SalvagePointName > 0)) { PrintPoint(point, sb); } sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); return(sb.ToString()); }
public static void PrintPoint(FLD_SalvagePointList point, Indenter sb) { sb.AppendLineAndIncrease("<div>"); sb.AppendLine($"<h2>{point._SalvagePointName.name}</h2>"); if (point.Condition != 0) { sb.AppendLine($"<h3>Condition {point.Condition}</h3>"); } sb.AppendLine("<table class=\"BtnChallenge\">"); sb.AppendLine("<tr><th>Button</th><th>Speed</th><th>Outer Ring</th><th>Inner Ring</th></tr>"); for (int i = 0; i < 3; i++) { MNU_BtnChallenge2 chal = point._BtnChallenge[i]; sb.AppendLine($"<tr><td>{chal._BtnType1}</td><td>{chal.Speed}</td><td>{chal._Param1.PushRange}</td><td>{chal._Param1.PushSweetRange}</td></tr>"); } sb.AppendLine("</table>"); for (int i = 0; i < 4; i++) { sb.AppendLine($"<h4>{GetCylinderQuality(i)} Cylinder<br/>"); sb.AppendLine($"Base treasure chance: {point._SalvageTable[i].TresureBoxHit / 100.0}%</h4>"); PrintSalvageTable(point._SalvageTable[i], sb); } sb.DecreaseAndAppendLine("</div>"); }
public static void PrintItemSet(FLD_SalvageItemSet table, Indenter sb) { if (table.RSC_ID != 0) { sb.AppendLine($"{GetTBoxType(table.RSC_ID)} treasure box<br/>"); } if (table.goldMin != 0) { sb.AppendLine($"{table.goldMin} - {table.goldMax} Gold<br/>"); } if (table.randitmPopMin == table.randitmPopMax) { sb.AppendLine($"{table.randitmPopMin} Items<br/>"); } else { sb.AppendLine($"{table.randitmPopMin} - {table.randitmPopMax} Items<br/>"); } sb.AppendLine("<br/>"); sb.AppendLine("</td></tr>"); for (int i = 0; i < 8; i++) { if (table._itmID[i] == null) { continue; } string itemName = GetItemName(table._itmID[i]); sb.AppendLine($"<tr><td>{itemName}</td><td>{table._itmPer[i] / 100.0:P}</td></tr>"); } sb.DecreaseAndAppendLine("</table>"); }
public static void PrintSalvageTable(FLD_SalvageTable table, Indenter sb) { sb.AppendLineAndIncrease("<table class=\"tbox\">"); for (int i = 0; i < 3; i++) { if (table._TresureTablePercent[i] == 0) { continue; } sb.AppendLine("<td>"); sb.AppendLineAndIncrease("<table>"); sb.AppendLine("<tr><td colspan=\"2\">"); sb.AppendLine($"Treasure Box {i + 1} {table._TresureTablePercent[i] / 10000.0:P}<br/>"); PrintItemSet(table._TresureTable[i], sb); sb.AppendLine("</td>"); } sb.DecreaseAndAppendLine("</table>"); }
public static void PrintIndex(BdatStringCollection bdats, string htmlDir) { var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine("<title>Xenoblade 2</title>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); sb.AppendLine("<h1>Xenoblade 2 data tables</h1>"); sb.AppendLine($"<p>{IndexText}</p>"); sb.AppendLine("<a href=\"chbtlrewards.html\">Challenge Battle Rewards</a><br/>"); sb.AppendLine("<h2><a href=\"bdat\\index.html\">Complete table list</a></h2>"); string prefix = bdats.Game.ToString().ToLower(); if (!File.Exists($"{prefix}_tableDisplay.csv")) { return; } using (var stream = new FileStream($"{prefix}_tableDisplay.csv", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new StreamReader(stream)) { IEnumerable <BdatFriendlyInfo> csv = new CsvReader(reader).GetRecords <BdatFriendlyInfo>(); IOrderedEnumerable <IGrouping <string, BdatFriendlyInfo> > grouped = csv.GroupBy(x => x.Group).OrderBy(x => x.Key); foreach (IGrouping <string, BdatFriendlyInfo> group in grouped) { sb.AppendLine($"<h2>{group.Key ?? "Other"}</h2>"); foreach (BdatFriendlyInfo tableInfo in group.OrderBy(x => x.Display)) { BdatStringTable table = bdats[tableInfo.TableName]; string path = Path.Combine("bdat", table.Filename ?? "", table.Name) + ".html"; sb.AppendLine($"<a href=\"{path}\">{tableInfo.Display}</a><br/>"); } } } sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); string filename = Path.Combine(htmlDir, "index.html"); File.WriteAllText(filename, sb.ToString()); }
public static void GenerateSaveCode() { var types = ReadTypes(); var sb = new Indenter(); bool first = true; sb.AppendLine("// ReSharper disable InconsistentNaming RedundantCast MemberCanBePrivate.Global NotAccessedField.Global FieldCanBeMadeReadOnly.Global ForCanBeConvertedToForeach PartialTypeWithSinglePart"); sb.AppendLine(""); sb.AppendLine("using XbTool.Types"); sb.AppendLine(); sb.AppendLine("namespace XbTool.Save"); sb.AppendLineAndIncrease("{"); foreach (var type in types) { if (!first) { sb.AppendLine(); } GenerateClass(type, sb); first = false; } sb.DecreaseAndAppendLine("}"); File.WriteAllText("SaveTypes.cs", sb.ToString()); }
private static string PrintDropTables(List <Enemy> enemies) { var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine($"<title>Xenoblade 1 Enemy Drop Tables</title>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); foreach (var enemy in enemies) { PrintEnemy(enemy, sb); } sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); return(sb.ToString()); }
public static void PrintSeparateTables(BdatStringCollection bdats, BdatInfo info, string htmlDir) { string bdatHtmlDir = Path.Combine(htmlDir, "bdat"); Directory.CreateDirectory(htmlDir); PrintIndex(bdats, htmlDir); foreach (string tableName in bdats.Tables.Keys) { string outDir = bdatHtmlDir; string tableFilename = bdats[tableName].Filename; var indexPath = tableFilename == null ? "../index.html" : "../../index.html"; var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine($"<title>{tableName}</title>"); sb.AppendLineAndIncrease("<script>"); sb.AppendLine(JsOpenAll); sb.DecreaseAndAppendLine("</script>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); sb.AppendLine($"<a href=\"{indexPath}\">Return to BDAT index</a><br/>"); sb.AppendLine("<input type=\"button\" value=\"Open all references\" onclick=\"openAll(true)\" />"); sb.AppendLine("<input type=\"button\" value=\"Close all references\" onclick=\"openAll(false)\" />"); PrintTable(bdats, info, tableName, sb); sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); if (tableFilename != null) { outDir = Path.Combine(outDir, tableFilename); } string filename = Path.Combine(outDir, tableName + ".html"); Directory.CreateDirectory(outDir); File.WriteAllText(filename, sb.ToString()); } }
public static string PrintHtml(BdatCollection tables) { var sb = new Indenter(); List <RewardSet> rewards = ReadAllRewards(tables); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLine("<html>"); sb.AppendLine("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine("<title>Xenoblade 2 Challenge Battle Rewards</title>"); sb.AppendLine("</head>"); sb.AppendLine("<body>"); sb.AppendLine("<pre>"); foreach (var chBtl in rewards) { foreach (var set in chBtl.Rewards) { sb.AppendLine($"{chBtl.Name} Treasure Box {set.BoxNum}"); sb.AppendLine($"Need {set.Need} Ether Cubes"); sb.AppendLine($"{set.AppointItem} x{set.AppointCount}"); sb.AppendLine($"{set.MinGold}-{set.MaxGold} gold"); sb.AppendLine($"{set.MinItems}-{set.MaxItems} items:"); var table = new Table("Name", "Prob"); foreach (var item in set.Items) { table.AddRow(item.Name, item.Percent.ToString("P")); } sb.AppendLine(table.Print()); sb.AppendLine(); } } sb.AppendLine("</pre>"); sb.AppendLine("</body>"); sb.AppendLine("</html>"); return(sb.ToString()); }
private static void CreateReadFunction(SaveType type, Indenter sb) { sb.AppendLine(); sb.AppendLine($"public {type.Name}(DataBuffer save)"); sb.AppendLineAndIncrease("{"); bool firstField = true; bool prevWasArray = false; foreach (var field in type.Fields) { switch (field.Type) { case "Scalar": if (prevWasArray) { sb.AppendLine(); } if (field.DataType == "string") { sb.AppendLine(GetReadValue(field)); } else { sb.AppendLine($"{field.Name} = {GetReadValue(field)}"); } prevWasArray = false; break; case "Array": if (!firstField) { sb.AppendLine(); } sb.AppendLine($"for (int i = 0; i < {field.Name}.Length; i++)"); sb.AppendLineAndIncrease("{"); sb.AppendLine($"{field.Name}[i] = {GetReadValue(field)}"); sb.DecreaseAndAppendLine("}"); prevWasArray = true; break; case "Bitfield": sb.AppendLine($"{field.DataType} {field.Name} = {GetReadValue(field)}"); int bit = 0; foreach (var value in field.Bitfield) { sb.AppendLine( $"{value.Name} = ({field.DataType})({field.Name} >> {bit} & ((1u << {value.Size}) - 1));"); bit += int.Parse(value.Size); } break; case "BitfieldArray": sb.AppendLine($"Read.ReadBitfieldArray(save, {field.Name}, {field.Length}, {field.Size});"); break; case "Padding": sb.AppendLine($"save.Position += {field.Length};"); break; } firstField = false; } sb.DecreaseAndAppendLine("}"); }
public static void PrintSeparateTables(BdatStringCollection bdats, string htmlDir, IProgressReport progress = null) { progress?.LogMessage("Writing BDAT tables as HTML"); progress?.SetTotal(bdats.Tables.Count); string bdatHtmlDir = Path.Combine(htmlDir, "bdat"); Directory.CreateDirectory(bdatHtmlDir); if (bdats.Game == Game.XB2) { PrintIndex(bdats, htmlDir); } PrintBdatIndex(bdats, bdatHtmlDir); foreach (string tableName in bdats.Tables.Keys) { string outDir = bdatHtmlDir; string tableFilename = bdats[tableName].Filename; string indexPath = tableFilename == null ? "index.html" : "../index.html"; var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine($"<title>{tableName}</title>"); sb.AppendLineAndIncrease("<style>"); sb.AppendLine(CssSticky); sb.AppendLine(CssSortable); sb.DecreaseAndAppendLine("</style>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); sb.AppendLine($"<a href=\"{indexPath}\">Return to BDAT index</a><br/>"); sb.AppendLine("<input type=\"button\" value=\"Open all references\" onclick=\"openAll(true)\" />"); sb.AppendLine("<input type=\"button\" value=\"Close all references\" onclick=\"openAll(false)\" />"); PrintTable(bdats[tableName], sb); sb.AppendLineAndIncrease("<script>"); sb.AppendLine(JsOpenAll); sb.AppendLine(JsSortable); sb.AppendLine(JsAnchor); sb.DecreaseAndAppendLine("</script>"); sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); if (tableFilename != null) { outDir = Path.Combine(outDir, tableFilename); } string filename = Path.Combine(outDir, tableName + ".html"); Directory.CreateDirectory(outDir); File.WriteAllText(filename, sb.ToString()); progress?.ReportAdd(1); } }
public static void PrintTable(BdatStringTable table, Indenter sb) { sb.AppendLineAndIncrease("<table class=\"sortable\">"); sb.AppendLineAndIncrease("<thead>"); sb.AppendLineAndIncrease("<tr id=\"header\">"); sb.AppendLine("<th class=\" dir-d \">ID</th>"); sb.AppendLine("<th>Referenced By</th>"); foreach (BdatMember member in table.Members) { if (member.Metadata?.Type == BdatFieldType.Hide) { continue; } bool sticky = table.DisplayMember == member.Name; string cellTag = $"<th{(sticky ? " class=\"side\"" : "")}"; switch (member.Type) { case BdatMemberType.Scalar: case BdatMemberType.Flag: sb.AppendLine($"{cellTag}>{member.Name}</th>"); break; case BdatMemberType.Array: sb.AppendLine($"{cellTag} colspan=\"{member.ArrayCount}\">{member.Name}</th>"); break; } } sb.DecreaseAndAppendLine("</tr>"); sb.DecreaseAndAppendLine("</thead>"); foreach (BdatStringItem item in table.Items.Where(x => x != null)) { sb.AppendLineAndIncrease($"<tr id=\"{item.Id}\">"); sb.AppendLine($"<td>{item.Id}</td>"); sb.AppendLineAndIncrease("<td>"); if (item.ReferencedBy.Count > 0) { sb.AppendLineAndIncrease("<details>"); sb.AppendLine($"<summary>{item.ReferencedBy.Count} refs</summary>"); foreach (BdatStringItem a in item.ReferencedBy.OrderBy(x => x.Table.Name).ThenBy(x => x.Id)) { string link = GetLink(table, a.Table, a.Id.ToString()); string display = (string)a.Display?.Display ?? a.Id.ToString(); if (string.IsNullOrWhiteSpace(display)) { display = a.Id.ToString(); } sb.AppendLine($"<a href=\"{link}\">{a.Table.Name}#{display}</a>"); } sb.DecreaseAndAppendLine("</details>"); } sb.DecreaseAndAppendLine("</td>"); foreach (BdatStringValue value in item.Values.Values) { BdatMember member = value.Member; if (member.Metadata?.Type == BdatFieldType.Hide) { continue; } bool sticky = value.Parent.Display == value; string cellTag = $"<td{(sticky ? " class=\"side\"" : "")}>"; switch (member.Type) { case BdatMemberType.Scalar: case BdatMemberType.Flag: PrintValue(value, cellTag); break; case BdatMemberType.Array: foreach (BdatStringValue arrValue in value.Array) { PrintValue(arrValue, cellTag); } break; } } sb.DecreaseAndAppendLine("</tr>"); } sb.DecreaseAndAppendLine("</table>"); void PrintValue(BdatStringValue value, string cellTag) { BdatStringItem child = value.Reference; if (child != null) { string display = child.Display?.DisplayString; if (string.IsNullOrWhiteSpace(display)) { display = child.Id.ToString(); } string link = GetLink(table, child.Table, child.Id.ToString()); sb.AppendLine($"{cellTag}<a href=\"{link}\">{WebUtility.HtmlEncode(display)}</td></a>"); } else { sb.AppendLine($"{cellTag}{WebUtility.HtmlEncode(value.DisplayString)}</td>"); } } }
public static void PrintTable(BdatStringCollection tables, BdatInfo info, string tableName, Indenter sb) { BdatStringTable table = tables[tableName]; sb.AppendLineAndIncrease("<table border=\"1\">"); sb.AppendLineAndIncrease("<thead>"); sb.AppendLineAndIncrease("<tr>"); sb.AppendLine("<th>ID</th>"); sb.AppendLine("<th>Referenced By</th>"); foreach (BdatMember member in table.Members) { if (info.FieldInfo.TryGetValue((tableName, member.Name), out var field)) { if (field.Type == BdatFieldType.Hide) { continue; } } switch (member.Type) { case BdatMemberType.Scalar: case BdatMemberType.Flag: sb.AppendLine($"<th>{member.Name}</th>"); break; case BdatMemberType.Array: sb.AppendLine($"<th colspan=\"{member.ArrayCount}\">{member.Name}</th>"); break; } } sb.DecreaseAndAppendLine("</tr>"); sb.DecreaseAndAppendLine("</thead>"); int id = table.BaseId; foreach (BdatStringItem item in table.Items) { sb.AppendLineAndIncrease($"<tr id=\"{id}\">"); sb.AppendLine($"<td>{id}</td>"); sb.AppendLineAndIncrease("<td>"); if (item.ReferencedBy.Count > 0) { sb.AppendLineAndIncrease("<details>"); sb.AppendLine($"<summary>{item.ReferencedBy.Count} refs</summary>"); foreach (var a in item.ReferencedBy) { var link = GetLink(table, tables[a.Table], a.Id.ToString()); string display = a.Id.ToString(); if (info.DisplayFields.TryGetValue(a.Table, out var displayField)) { var child = BdatStringTools.ReadValue(a.Table, a.Id, displayField, tables, info); if (!string.IsNullOrWhiteSpace(child.value)) { display = child.value; } } sb.AppendLine($"<a href=\"{link}\">{a.Table}#{display}</a>"); } sb.DecreaseAndAppendLine("</details>"); } sb.DecreaseAndAppendLine("</td>"); foreach (BdatMember member in table.Members) { if (info.FieldInfo.TryGetValue((tableName, member.Name), out var field)) { if (field.Type == BdatFieldType.Hide) { continue; } } switch (member.Type) { case BdatMemberType.Scalar: case BdatMemberType.Flag: var val = BdatStringTools.ReadValue(tableName, id, member.Name, tables, info); if (val.childTable != null) { var link = GetLink(table, tables[val.childTable], val.childId); sb.AppendLine($"<td><a href=\"{link}\">{val.value}</td></a>"); } else { sb.AppendLine($"<td>{val.value}</td>"); } break; case BdatMemberType.Array: var arr = (string[])item.Values[member.Name]; foreach (string value in arr) { sb.AppendLine($"<td>{value}</td>"); } break; } } sb.DecreaseAndAppendLine("</tr>"); id++; } sb.DecreaseAndAppendLine("</table>"); }
private static void PrintEnemy(Enemy enemy, Indenter sb) { sb.AppendLine($"<h2>{enemy.Name} (#{enemy.Id})</h2>"); sb.AppendLineAndIncrease("<table>"); sb.AppendLine($"<tr><td>Normal</td><td>{enemy.NormalDropRate:P2}</td>"); sb.AppendLine($"<tr><td>Rare</td><td>{enemy.RareDropRate:P2}</td>"); sb.AppendLine($"<tr><td>Super Rare</td><td>{enemy.SuperRareDropRate:P2}</td>"); sb.DecreaseAndAppendLine("</table>"); if (enemy.HasNormalDrops()) { sb.AppendLine("<h3>Normal:</h3>"); sb.AppendLine("<h4>Materials (From normal chest)</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.NormalDrops.MaterialsDouble.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); sb.AppendLine("<h4>Materials (From other chests)</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.NormalDrops.MaterialsSingle.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.HasRareDrops()) { sb.AppendLine("<h3>Rare:</h3>"); if (enemy.RareDrops.Crystals.Any(x => x.TotalDropRate != 0)) { if (enemy.RareDrops.Crystals.Any(x => x.Item.IsCylinder)) { sb.AppendLine("<h4>Cylinders</h4>"); } else { sb.AppendLine("<h4>Crystals</h4>"); } sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.RareDrops.Crystals.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.GetDisplayString()}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.RareDrops.Weapons.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Weapons</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.RareDrops.Weapons.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{GetSlotsString(item.SlotCount)}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.RareDrops.Armor.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Armor</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.RareDrops.Armor.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{GetSlotsString(item.SlotCount)}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.RareDrops.ArtBooks.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Art Books</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.RareDrops.ArtBooks.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } } if (enemy.HasSuperRareDrops()) { sb.AppendLine("<h3>Super Rare:</h3>"); if (enemy.SuperRareDrops.Weapons.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Weapons</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.SuperRareDrops.Weapons.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{GetSlotsString(item.SlotCount)}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.SuperRareDrops.UniqueWeapons.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Unique Weapons</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.SuperRareDrops.UniqueWeapons.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.SuperRareDrops.UniqueArmor.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Unique Armor</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.SuperRareDrops.UniqueArmor.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } if (enemy.SuperRareDrops.ArtBooks.Any(x => x.TotalDropRate != 0)) { sb.AppendLine("<h4>Art Books</h4>"); sb.AppendLineAndIncrease("<table>"); foreach (var item in enemy.SuperRareDrops.ArtBooks.OrderDrops()) { sb.AppendLine($"<tr><td>{item.Item.Name}</td><td>{item.TotalDropRate:P2}</td>"); } sb.DecreaseAndAppendLine("</table>"); } } }