// Emit a C# enum of every spell in portal.dat's SpellTable. // // Generated rather than hand-written or copied from another project: the ids // and names come from the user's own game data, so the enum cannot drift from // what the client actually loads, and regenerating is a one-liner. using System.Text; using AcDream.Core.Spells; namespace SpellDump; internal static class EmitEnum { public static void Run(SpellTable table, string outPath, string ns, string typeName) { var byName = new Dictionary(StringComparer.Ordinal); var ordered = new List<(uint Id, string Ident, string Name)>(); foreach (uint id in table.SpellIds.OrderBy(i => i)) { if (!table.TryGet(id, out SpellMetadata meta)) continue; string ident = Identifier(meta.Name); if (ident.Length == 0) ident = "Spell"; // Retail reuses display names across ids; suffix collisions with the // id so every member stays addressable and stable. if (byName.ContainsKey(ident)) ident = $"{ident}_{id:X4}"; byName[ident] = id; ordered.Add((id, ident, meta.Name)); } var sb = new StringBuilder(); sb.AppendLine("// "); sb.AppendLine("// Generated by tools/SpellDump from portal.dat's SpellTable (0x0E00000E)."); sb.AppendLine("// Do not edit by hand. Regenerate with:"); sb.AppendLine("// dotnet run --project tools/SpellDump -- --enum"); sb.AppendLine("// "); sb.AppendLine(); sb.AppendLine($"namespace {ns};"); sb.AppendLine(); sb.AppendLine("/// Every spell id in the retail spell table, by name."); sb.AppendLine($"public enum {typeName} : uint"); sb.AppendLine("{"); foreach (var (id, ident, name) in ordered) { sb.AppendLine($" /// {System.Security.SecurityElement.Escape(name)}"); sb.AppendLine($" {ident} = 0x{id:X4},"); } sb.AppendLine("}"); File.WriteAllText(outPath, sb.ToString()); Console.WriteLine($"wrote {outPath}: {ordered.Count} spells"); } private static string Identifier(string name) { var sb = new StringBuilder(name.Length); bool upper = true; foreach (char c in name) { if (char.IsLetterOrDigit(c)) { sb.Append(upper ? char.ToUpperInvariant(c) : c); upper = false; } else { upper = true; // word break -> PascalCase } } string ident = sb.ToString(); if (ident.Length > 0 && char.IsDigit(ident[0])) ident = "S" + ident; return ident; } }