private List<string> ExportCPP(TextWriter writer, bool SA2) { ModelFormat modelfmt = SA2 ? ModelFormat.Chunk : ModelFormat.BasicDX; LandTableFormat landfmt = SA2 ? LandTableFormat.SA2 : LandTableFormat.SADX; writer.WriteLine("// Generated by SA Tools DLL Mod Generator"); writer.WriteLine(); if (SA2) writer.WriteLine("#include \"SA2ModLoader.h\""); else writer.WriteLine("#include \"SADXModLoader.h\""); writer.WriteLine(); List<string> labels = new List<string>(); foreach (KeyValuePair<string, FileTypeHash> item in IniData.Files.Where((a, i) => listView1.CheckedIndices.Contains(i))) switch (item.Value.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(item.Key); writer.WriteLine(tbl.ToStructVariables(landfmt, new List<string>())); labels.AddRange(tbl.GetLabels()); break; case "model": SonicRetro.SAModel.NJS_OBJECT mdl = new ModelFile(item.Key).Model; writer.WriteLine(mdl.ToStructVariables(modelfmt == ModelFormat.BasicDX, new List<string>())); labels.AddRange(mdl.GetLabels()); break; case "basicmodel": case "chunkmodel": mdl = new ModelFile(item.Key).Model; writer.WriteLine(mdl.ToStructVariables(false, new List<string>())); labels.AddRange(mdl.GetLabels()); break; case "basicdxmodel": mdl = new ModelFile(item.Key).Model; writer.WriteLine(mdl.ToStructVariables(true, new List<string>())); labels.AddRange(mdl.GetLabels()); break; case "animation": Animation ani = Animation.Load(item.Key); writer.WriteLine(ani.ToStructVariables()); labels.Add(ani.Name); break; } return labels; }
private void ExportCPP(TextWriter writer, bool SA2) { Dictionary<uint, string> pointers = new Dictionary<uint, string>(); uint imagebase = IniData.ImageBase ?? 0x400000; ModelFormat modelfmt = 0; LandTableFormat landfmt = 0; switch (IniData.Game) { case Game.SA1: modelfmt = ModelFormat.Basic; landfmt = LandTableFormat.SA1; break; case Game.SADX: modelfmt = ModelFormat.BasicDX; landfmt = LandTableFormat.SADX; break; case Game.SA2: case Game.SA2B: modelfmt = ModelFormat.Chunk; landfmt = LandTableFormat.SA2; break; } writer.WriteLine("// Generated by SA Tools Struct Converter"); writer.WriteLine(); if (SA2) writer.WriteLine("#include \"SA2ModLoader.h\""); else writer.WriteLine("#include \"SADXModLoader.h\""); writer.WriteLine(); Dictionary<string, string> models = new Dictionary<string, string>(); foreach (KeyValuePair<string, SA_Tools.FileInfo> item in IniData.Files.Where((a, i) => listView1.CheckedIndices.Contains(i))) { string name = item.Key.MakeIdentifier(); SA_Tools.FileInfo data = item.Value; switch (data.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(data.Filename); name = tbl.Name; writer.WriteLine(tbl.ToStructVariables(landfmt, new List<string>())); break; case "model": SonicRetro.SAModel.NJS_OBJECT mdl = new ModelFile(data.Filename).Model; name = mdl.Name; writer.WriteLine(mdl.ToStructVariables(modelfmt == ModelFormat.BasicDX, new List<string>())); models.Add(item.Key, mdl.Name); break; case "basicmodel": mdl = new SonicRetro.SAModel.ModelFile(data.Filename).Model; name = mdl.Name; writer.WriteLine(mdl.ToStructVariables(false, new List<string>())); models.Add(item.Key, mdl.Name); break; case "basicdxmodel": mdl = new SonicRetro.SAModel.ModelFile(data.Filename).Model; name = mdl.Name; writer.WriteLine(mdl.ToStructVariables(true, new List<string>())); models.Add(item.Key, mdl.Name); break; case "chunkmodel": mdl = new SonicRetro.SAModel.ModelFile(data.Filename).Model; name = mdl.Name; writer.WriteLine(mdl.ToStructVariables(false, new List<string>())); models.Add(item.Key, mdl.Name); break; case "action": Animation ani = Animation.Load(data.Filename); name = "action_" + ani.Name.MakeIdentifier(); writer.WriteLine(ani.ToStructVariables()); writer.WriteLine("NJS_ACTION {0} = {{ &{1}, &{2} }};", name, models[data.CustomProperties["model"]], ani.Name.MakeIdentifier()); break; case "animation": ani = Animation.Load(data.Filename); name = ani.Name.MakeIdentifier(); writer.WriteLine(ani.ToStructVariables()); break; case "objlist": { ObjectListEntry[] list = ObjectList.Load(data.Filename, SA2); writer.WriteLine("ObjectListEntry {0}_list[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (ObjectListEntry obj in list) objs.Add(obj.ToStruct() + " " + obj.Name.ToComment()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); writer.WriteLine("ObjectList {0} = {{ arraylengthandptr({0}_list) }};", name); } break; case "startpos": if (SA2) { Dictionary<SA2LevelIDs, SA2StartPosInfo> list = SA2StartPosList.Load(data.Filename); writer.WriteLine("StartPosition {0}[] = {{", name); List<string> objs = new List<string>(list.Count + 1); foreach (KeyValuePair<SA2LevelIDs, SA2StartPosInfo> obj in list) objs.Add(obj.ToStruct()); objs.Add("{ LevelIDs_Invalid }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } else { Dictionary<SA1LevelAct, SA1StartPosInfo> list = SA1StartPosList.Load(data.Filename); writer.WriteLine("StartPosition {0}[] = {{", name); List<string> objs = new List<string>(list.Count + 1); foreach (KeyValuePair<SA1LevelAct, SA1StartPosInfo> obj in list) objs.Add(obj.ToStruct()); objs.Add("{ LevelIDs_Invalid }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "texlist": { TextureListEntry[] list = TextureList.Load(data.Filename); writer.WriteLine("PVMEntry {0}[] = {{", name); List<string> objs = new List<string>(list.Length + 1); foreach (TextureListEntry obj in list) objs.Add(obj.ToStruct()); objs.Add("{ 0 }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "leveltexlist": { LevelTextureList list = LevelTextureList.Load(data.Filename); writer.WriteLine("PVMEntry {0}_list[] = {{", name); List<string> objs = new List<string>(list.TextureList.Length); foreach (TextureListEntry obj in list.TextureList) objs.Add(obj.ToStruct()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); writer.WriteLine("LevelPVMList {0} = {{ {1}, arraylengthandptr({0}_list) }};", name, list.Level.ToC()); } break; case "triallevellist": { SA1LevelAct[] list = TrialLevelList.Load(data.Filename); writer.WriteLine("TrialLevelListEntry {0}_list[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (SA1LevelAct obj in list) objs.Add(string.Format("{{ {0}, {1} }}", obj.Level.ToC("LevelIDs"), obj.Act)); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); writer.WriteLine("TrialLevelList {0} = {{ arrayptrandlength({0}_list) }};", name); } break; case "bosslevellist": { SA1LevelAct[] list = BossLevelList.Load(data.Filename); writer.WriteLine("__int16 {0}[] = {{", name); List<string> objs = new List<string>(list.Length + 1); foreach (SA1LevelAct obj in list) objs.Add(obj.ToC()); objs.Add("levelact(LevelIDs_Invalid, 0)"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "fieldstartpos": { Dictionary<SA1LevelIDs, FieldStartPosInfo> list = FieldStartPosList.Load(data.Filename); writer.WriteLine("FieldStartPosition {0}[] = {{", name); List<string> objs = new List<string>(list.Count + 1); foreach (KeyValuePair<SA1LevelIDs, FieldStartPosInfo> obj in list) objs.Add(obj.ToStruct()); objs.Add("{ LevelIDs_Invalid }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "soundtestlist": { SoundTestListEntry[] list = SoundTestList.Load(data.Filename); writer.WriteLine("SoundTestEntry {0}_list[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (SoundTestListEntry obj in list) objs.Add(obj.ToStruct() + " " + obj.Title.ToComment()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); writer.WriteLine("SoundTestCategory {0} = {{ arrayptrandlength({0}_list) }};", name); } break; case "musiclist": { MusicListEntry[] list = MusicList.Load(data.Filename); writer.WriteLine("MusicInfo {0}[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (MusicListEntry obj in list) objs.Add(obj.ToStruct()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "soundlist": { SoundListEntry[] list = SoundList.Load(data.Filename); writer.WriteLine("SoundFileInfo {0}_list[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (SoundListEntry obj in list) objs.Add(obj.ToStruct()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); writer.WriteLine("SoundList {0} = {{ arraylengthandptr({0}_list) }};", name); } break; case "stringarray": { string[] strs = StringArray.Load(data.Filename); Languages lang = Languages.Japanese; if (data.CustomProperties.ContainsKey("language")) lang = (Languages)Enum.Parse(typeof(Languages), data.CustomProperties["language"], true); writer.WriteLine("char *{0}[] = {{", name); List<string> objs = new List<string>(strs.Length); foreach (string obj in strs) objs.Add(obj.ToC(lang) + " " + obj.ToComment()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "nextlevellist": { NextLevelListEntry[] list = NextLevelList.Load(data.Filename); writer.WriteLine("NextLevelData {0}[] = {{", name); List<string> objs = new List<string>(list.Length + 1); foreach (NextLevelListEntry obj in list) objs.Add(obj.ToStruct()); objs.Add("{ 0, -1 }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "cutscenetext": { CutsceneText texts = new CutsceneText(data.Filename); uint addr = (uint)(data.Address + imagebase); for (int j = 0; j < 5; j++) { string[] strs = texts.Text[j]; Languages lang = (Languages)j; writer.WriteLine("char *{0}_{1}[] = {{", name, lang); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", strs.Select((a) => a.ToC(lang) + " " + a.ToComment()).ToArray())); writer.WriteLine("};"); writer.WriteLine(); pointers.Add(addr, string.Format("{0}_{1}", name, lang)); addr += 4; } } break; case "recapscreen": { uint addr = (uint)(data.Address + imagebase); RecapScreen[][] texts = RecapScreenList.Load(data.Filename, int.Parse(data.CustomProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo)); for (int l = 0; l < 5; l++) for (int j = 0; j < texts.Length; j++) { writer.WriteLine("char *{0}_{1}_{2}_Text[] = {{", name, (Languages)l, j); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", texts[j][l].Text.Split('\n').Select((a) => a.ToC((Languages)l) + " " + a.ToComment()).ToArray())); writer.WriteLine("};"); writer.WriteLine(); } for (int l = 0; l < 5; l++) { writer.WriteLine("RecapScreen {0}_{1}[] = {{", name, (Languages)l); List<string> objs = new List<string>(texts.Length); for (int j = 0; j < texts.Length; j++) { RecapScreen scr = texts[j][l]; objs.Add(string.Format("{{ {0}, arraylengthandptr({1}_{2}_{3}_Text) }}", SA_Tools.HelperFunctions.ToC(scr.Speed), name, (Languages)l, j)); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); pointers.Add(addr, string.Format("{0}_{1}", name, (Languages)l)); addr += 4; } } break; case "npctext": { NPCText[][] texts = NPCTextList.Load(data.Filename, int.Parse(data.CustomProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo)); uint headaddr = (uint)(data.Address + imagebase); for (int l = 0; l < 5; l++) { for (int j = 0; j < texts[l].Length; j++) { if (texts[l][j].Groups.Count == 0) continue; if (texts[l][j].HasControl) { writer.WriteLine("__int16 {0}_{1}_{2}_Control[] = {{", name, (Languages)l, j); bool first = true; List<string> objs = new List<string>(); foreach (NPCTextGroup group in texts[l][j].Groups) { if (!first) objs.Add(NPCTextControl.NewGroup.ToC()); else first = false; foreach (ushort flag in group.EventFlags) { objs.Add(NPCTextControl.EventFlag.ToC()); objs.Add(flag.ToCHex()); } foreach (ushort flag in group.NPCFlags) { objs.Add(NPCTextControl.NPCFlag.ToC()); objs.Add(flag.ToCHex()); } if (group.Character != (SA1CharacterFlags)0xFF) { objs.Add(NPCTextControl.Character.ToC()); objs.Add(group.Character.ToC("CharacterFlags")); } if (group.Voice.HasValue) { objs.Add(NPCTextControl.Voice.ToC()); objs.Add(group.Voice.Value.ToString()); } if (group.SetEventFlag.HasValue) { objs.Add(NPCTextControl.SetEventFlag.ToC()); objs.Add(group.SetEventFlag.Value.ToCHex()); } } objs.Add(NPCTextControl.End.ToC()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); } if (texts[l][j].HasText) { writer.WriteLine("HintText_Text {0}_{1}_{2}_Text[] = {{", name, (Languages)l, j); List<string> objs = new List<string>(); foreach (NPCTextGroup group in texts[l][j].Groups) { foreach (NPCTextLine line in group.Lines) objs.Add(line.ToStruct((Languages)l) + " " + line.Line.ToComment()); objs.Add("{ 0 }"); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); } } } for (int l = 0; l < 5; l++) { if (l > 0) writer.WriteLine(); writer.WriteLine("HintText_Entry {0}_{1}[] = {{", name, (Languages)l); List<string> objs = new List<string>(); for (int j = 0; j < texts[l].Length; j++) { if (texts[l][j].Groups.Count == 0) { objs.Add("{ 0 }"); continue; } StringBuilder line = new StringBuilder("{ "); if (texts[l][j].HasControl) line.AppendFormat("{0}_{1}_{2}_Control", name, (Languages)l, j); else line.Append("NULL"); line.Append(", "); if (texts[l][j].HasText) line.AppendFormat("{0}_{1}_{2}_Text", name, (Languages)l, j); else line.Append("NULL"); line.Append(" }"); objs.Add(line.ToString()); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); pointers.Add(headaddr, string.Format("{0}_{1}", name, (Languages)l)); headaddr += 4; } } break; case "levelclearflags": { LevelClearFlag[] list = LevelClearFlagList.Load(data.Filename); writer.WriteLine("LevelClearFlagData {0}[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (LevelClearFlag obj in list) objs.Add(obj.ToStruct()); objs.Add("{ -1 }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "deathzone": { DeathZoneFlags[] list = DeathZoneFlagsList.Load(data.Filename); string path = Path.GetDirectoryName(data.Filename); List<string> mdls = new List<string>(list.Length); List<string> objs = new List<string>(); for (int j = 0; j < list.Length; j++) { SonicRetro.SAModel.NJS_OBJECT obj = new ModelFile(Path.Combine(path, j.ToString(NumberFormatInfo.InvariantInfo) + ".sa1mdl")).Model; writer.WriteLine(obj.ToStructVariables(modelfmt == ModelFormat.BasicDX, objs)); mdls.Add(obj.Name); objs.Clear(); } writer.WriteLine("DeathZone {0}[] = {{", name); for (int j = 0; j < list.Length; j++) objs.Add(string.Format("{{ {0}, &{1} }}", list[j].Flags.ToC("CharacterFlags"), mdls[j])); objs.Add("{ 0 }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "skyboxscale": { uint headaddr = (uint)(data.Address + imagebase); int cnt = int.Parse(data.CustomProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo); SkyboxScale[] sclini = SkyboxScaleList.Load(data.Filename); for (int j = 0; j < cnt; j++) { writer.WriteLine("SkyboxScale {0}_{1} = {2};", name, j, sclini[j].ToStruct()); pointers.Add(headaddr, string.Format("{0}_{1}", name, j)); headaddr += 4; } } break; case "stageselectlist": { StageSelectLevel[] list = StageSelectLevelList.Load(data.Filename); writer.WriteLine("StageSelectLevel {0}[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (StageSelectLevel obj in list) objs.Add(obj.ToStruct()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "levelrankscores": { Dictionary<SA2LevelIDs, LevelRankScores> list = LevelRankScoresList.Load(data.Filename); writer.WriteLine("LevelRankScores {0}[] = {{", name); List<string> objs = new List<string>(list.Count); foreach (KeyValuePair<SA2LevelIDs, LevelRankScores> obj in list) objs.Add(obj.ToStruct()); objs.Add("{ LevelIDs_Invalid }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "levelranktimes": { Dictionary<SA2LevelIDs, LevelRankTimes> list = LevelRankTimesList.Load(data.Filename); writer.WriteLine("LevelRankTimes {0}[] = {{", name); List<string> objs = new List<string>(list.Count); foreach (KeyValuePair<SA2LevelIDs, LevelRankTimes> obj in list) objs.Add(obj.ToStruct()); objs.Add("{ LevelIDs_Invalid }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "endpos": { Dictionary<SA2LevelIDs, SA2EndPosInfo> list = SA2EndPosList.Load(data.Filename); writer.WriteLine("LevelEndPosition {0}[] = {{", name); List<string> objs = new List<string>(list.Count); foreach (KeyValuePair<SA2LevelIDs, SA2EndPosInfo> obj in list) objs.Add(obj.ToStruct()); objs.Add("{ LevelIDs_Invalid }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "animationlist": { SA2AnimationInfo[] list = SA2AnimationInfoList.Load(data.Filename); writer.WriteLine("AnimationInfo {0}[] = {{", name); List<string> objs = new List<string>(list.Length); foreach (SA2AnimationInfo obj in list) objs.Add(obj.ToStruct()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "levelpathlist": { List<SA1LevelAct> levels = new List<SA1LevelAct>(); foreach (string dir in Directory.GetDirectories(data.Filename)) { SA1LevelAct level; try { level = new SA1LevelAct(new DirectoryInfo(dir).Name); } catch { continue; } levels.Add(level); List<PathData> paths = PathList.Load(dir); for (int i = 0; i < paths.Count; i++) { writer.WriteLine("Loop {0}_{1}_{2}_Entries[] = {{", name, level.ToString().MakeIdentifier(), i); List<string> objs = new List<string>(paths[i].Path.Count); foreach (PathDataEntry entry in paths[i].Path) objs.Add(entry.ToStruct()); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); writer.WriteLine("LoopHead {0}_{1}_{2} = {{ {3}, LengthOfArray({0}_{1}_{2}_Entries), {4}, {0}_{1}_{2}_Entries, (ObjectFuncPtr){5} }};", name, level.ToString().MakeIdentifier(), i, paths[i].Unknown, HelperFunctions.ToC(paths[i].TotalDistance), HelperFunctions.ToCHex(paths[i].Code)); writer.WriteLine(); } writer.WriteLine("LoopHead *{0}_{1}[] = {{", name, level.ToString().MakeIdentifier()); for (int i = 0; i < paths.Count; i++) writer.WriteLine("\t&{0}_{1}_{2},", name, level.ToString().MakeIdentifier(), i); writer.WriteLine("\tNULL"); writer.WriteLine("};"); writer.WriteLine(); } writer.WriteLine("PathDataPtr {0}[] = {{", name); foreach (SA1LevelAct level in levels) writer.WriteLine("\t{{ {0}, {1}_{2} }},", level.ToC(), name, level.ToString().MakeIdentifier()); writer.WriteLine("\t{ 0xFFFF }"); writer.WriteLine("};"); writer.WriteLine(); } break; case "stagelightdatalist": { List<SA1StageLightData> list = SA1StageLightDataList.Load(data.Filename); writer.WriteLine("StageLightData {0}[] = {{", name); List<string> objs = new List<string>(list.Count + 1); foreach (SA1StageLightData obj in list) objs.Add(obj.ToStruct()); objs.Add("{ 0xFFu }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; } writer.WriteLine(); if (data.PointerList != null && data.PointerList.Length > 0) foreach (int ptr in data.PointerList) pointers.Add((uint)(ptr + imagebase), name); } writer.WriteLine("PointerInfo pointers[] = {"); List<string> ptrs = new List<string>(pointers.Count); foreach (KeyValuePair<uint, string> ptr in pointers) ptrs.Add(string.Format("ptrdecl({0}, &{1})", HelperFunctions.ToCHex(ptr.Key), ptr.Value)); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", ptrs.ToArray())); writer.WriteLine("};"); writer.WriteLine(); }