diff --git a/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.Event/Schemas/ReleasePokeTableArray.fbs b/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.Event/Schemas/ReleasePokeTableArray.fbs index 0c7e4b68..80e7309c 100644 --- a/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.Event/Schemas/ReleasePokeTableArray.fbs +++ b/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.Event/Schemas/ReleasePokeTableArray.fbs @@ -4,10 +4,6 @@ include "Shared/ItemID.fbs"; namespace pkNX.Structures.FlatBuffers.SV; attribute "fs_serializer"; -table ReleasePokeTableArray (fs_serializer) { - Table:[ReleasePokeTable]; -} - table ReleasePokeTable { EventId:int; StateWorkName:string; @@ -19,4 +15,8 @@ table ReleasePokeTable { TeamMissionB:bool; } +table ReleasePokeTableArray (fs_serializer) { + Table:[ReleasePokeTable] (required); +} + root_type ReleasePokeTableArray; diff --git a/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.World/Schemas/MissionSettingsArray.fbs b/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.World/Schemas/MissionSettingsArray.fbs index 783244df..9460ac83 100644 --- a/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.World/Schemas/MissionSettingsArray.fbs +++ b/pkNX.Structures.FlatBuffers.SV/pkNX.Structures.FlatBuffers.SV.World/Schemas/MissionSettingsArray.fbs @@ -3,14 +3,14 @@ include "MissionType.fbs"; namespace pkNX.Structures.FlatBuffers.SV; attribute "fs_serializer"; -table MissionSettingsArray (fs_serializer) { - Table:[MissionSettings]; -} - table MissionSettings { MissionType:MissionType; Variation:int; Text:string; } +table MissionSettingsArray (fs_serializer) { + Table:[MissionSettings] (required); +} + root_type MissionSettingsArray; diff --git a/pkNX.Tests/pkNX.Tests.FileSystem/pkNX.Tests.FileSystem.csproj b/pkNX.Tests/pkNX.Tests.FileSystem/pkNX.Tests.FileSystem.csproj index 649d84c3..169adeca 100644 --- a/pkNX.Tests/pkNX.Tests.FileSystem/pkNX.Tests.FileSystem.csproj +++ b/pkNX.Tests/pkNX.Tests.FileSystem/pkNX.Tests.FileSystem.csproj @@ -10,8 +10,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/pkNX.Tests/pkNX.Tests.Trinity/pkNX.Tests.Trinity.csproj b/pkNX.Tests/pkNX.Tests.Trinity/pkNX.Tests.Trinity.csproj index 7af7c1f6..9629d0cc 100644 --- a/pkNX.Tests/pkNX.Tests.Trinity/pkNX.Tests.Trinity.csproj +++ b/pkNX.Tests/pkNX.Tests.Trinity/pkNX.Tests.Trinity.csproj @@ -10,8 +10,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/pkNX.WinForms/Dumping/GameDumperSV.cs b/pkNX.WinForms/Dumping/GameDumperSV.cs index 00840ca5..40203f53 100644 --- a/pkNX.WinForms/Dumping/GameDumperSV.cs +++ b/pkNX.WinForms/Dumping/GameDumperSV.cs @@ -546,12 +546,14 @@ private void DumpEncount() Dump("world/data/encount/point_data/point_data/encount_data_100000.bfbs", z => z.Table); Dump("world/data/encount/point_data/point_data/encount_data_su1.bfbs", z => z.Table); Dump("world/data/encount/point_data/point_data/encount_data_su2.bfbs", z => z.Table); + //Dump("world/data/encount/point_data/point_data/encount_data_lc.bfbs", z => z.Table); -- no points (null array) Dump("world/data/encount/point_data/outbreak_point_data/outbreak_point_main.bfbs", z => z.Table); Dump("world/data/encount/point_data/outbreak_point_data/outbreak_point_su1.bfbs", z => z.Table); Dump("world/data/encount/point_data/outbreak_point_data/outbreak_point_su2.bfbs", z => z.Table); Dump("world/data/encount/pokedata/pokedata/pokedata_array.bfbs", z => z.Table); Dump("world/data/encount/pokedata/pokedata_su1/pokedata_su1_array.bfbs", z => z.Table); Dump("world/data/encount/pokedata/pokedata_su2/pokedata_su2_array.bfbs", z => z.Table); + Dump("world/data/encount/pokedata/pokedata_lc/pokedata_lc_array.bfbs", z => z.Table); DumpJson("world/data/encount/setting/setting/data.bfbs"); Dump("world/data/encount/setting/raid_difficulty_lottery/raid_difficulty_lottery_array.bfbs", z => z.Table); DumpJson("world/data/encount/setting/raid_gem_setting/raid_gem_setting.bfbs"); @@ -748,11 +750,13 @@ private void DumpItems() Dump("world/data/item/hiddenItemBiomeTable/hiddenItemBiomeTable_array.bfbs", z => z.Table); Dump("world/data/item/hiddenItemBiomeTable_su1/hiddenItemBiomeTable_su1_array.bfbs", z => z.Table); Dump("world/data/item/hiddenItemBiomeTable_su2/hiddenItemBiomeTable_su2_array.bfbs", z => z.Table); + Dump("world/data/item/hiddenItemBiomeTable_lc/hiddenItemBiomeTable_lc_array.bfbs", z => z.Table); Dump("world/data/item/dropitemdata/dropitemdata_array.bfbs", z => z.Table); Dump("world/data/item/itemdata/itemdata_array.bfbs", z => z.Table); Dump("world/data/item/hiddenItemDataTable/hiddenItemDataTable_array.bfbs", z => z.Table); Dump("world/data/item/hiddenItemDataTable_su1/hiddenItemDataTable_su1_array.bfbs", z => z.Table); Dump("world/data/item/hiddenItemDataTable_su2/hiddenItemDataTable_su2_array.bfbs", z => z.Table); + Dump("world/data/item/hiddenItemDataTable_lc/hiddenItemDataTable_lc_array.bfbs", z => z.Table); Dump("world/data/item/monohiroiItemData/monohiroiItemData_array.bfbs", z => z.Table); } @@ -1106,12 +1110,14 @@ public void DumpSpecific() "world/data/encount/point_data/point_data/encount_data_100000.bfbs", "world/data/encount/point_data/point_data/encount_data_su1.bfbs", "world/data/encount/point_data/point_data/encount_data_su2.bfbs", + "world/data/encount/point_data/point_data/encount_data_lc.bfbs", "world/data/encount/point_data/outbreak_point_data/outbreak_point_main.bfbs", "world/data/encount/point_data/outbreak_point_data/outbreak_point_su1.bfbs", "world/data/encount/point_data/outbreak_point_data/outbreak_point_su2.bfbs", "world/data/encount/pokedata/pokedata/pokedata_array.bfbs", "world/data/encount/pokedata/pokedata_su1/pokedata_su1_array.bfbs", "world/data/encount/pokedata/pokedata_su2/pokedata_su2_array.bfbs", + "world/data/encount/pokedata/pokedata_lc/pokedata_lc_array.bfbs", "world/data/encount/setting/setting/data.bfbs", "world/data/encount/setting/raid_difficulty_lottery/raid_difficulty_lottery_array.bfbs", "world/data/encount/setting/raid_gem_setting/raid_gem_setting.bfbs", diff --git a/pkNX.WinForms/Dumping/MassOutbreakRipper.cs b/pkNX.WinForms/Dumping/MassOutbreakRipper.cs index f314aeb2..7605e1ad 100644 --- a/pkNX.WinForms/Dumping/MassOutbreakRipper.cs +++ b/pkNX.WinForms/Dumping/MassOutbreakRipper.cs @@ -188,7 +188,7 @@ private static void ScanAssertions(params DeliveryOutbreakPokeDataArray[] obs) var areas = scene.AreaInfos[(int)fieldIndex]; var areaNames = scene.AreaNames[(int)fieldIndex]; - var atlantis = scene.IsAtlantis[(int)fieldIndex]; + var atlantis = scene.PaldeaType[(int)fieldIndex]; if (fieldIndex == PaldeaFieldIndex.Kitakami) { areas = areas.Where(z => z.Value.AdjustEncLv != 0) @@ -311,7 +311,7 @@ private static void AddToJar(IEnumerable encs) } private static (UInt128 Met, int Boost) GetMetFlags(PaldeaSceneModel scene, Dictionary placeNameMap, PaldeaFieldIndex fieldIndex, - byte baseMet, List areaNames, Dictionary areas, OutbreakPointData point, Dictionary atlantis) + byte baseMet, List areaNames, Dictionary areas, OutbreakPointData point, Dictionary atlantis) { UInt128 result = 0; int boost = 0; @@ -319,7 +319,7 @@ private static void AddToJar(IEnumerable encs) { var areaName = areaNames[i]; var areaInfo = areas[areaName]; - if (atlantis[areaName]) + if (atlantis[areaName] != PaldeaPointPivot.Overworld) continue; if (areaInfo.Tag is AreaTag.NG_Encount) diff --git a/pkNX.WinForms/Dumping/SV/EncounterDumperSV.cs b/pkNX.WinForms/Dumping/SV/EncounterDumperSV.cs index 44f1abd0..9aa63180 100644 --- a/pkNX.WinForms/Dumping/SV/EncounterDumperSV.cs +++ b/pkNX.WinForms/Dumping/SV/EncounterDumperSV.cs @@ -20,10 +20,14 @@ public class EncounterDumperSV public EncounterDumperSV(IFileInternal rom) => ROM = rom; - private static readonly string[] BannedFixedSpawnNames = - { - "ai_area01_30", // Lighthouse Wingull - }; + private static readonly string[] BannedFixedSpawnNames = ["ai_area01_30"]; // Lighthouse Wingull + + private static ReadOnlySpan AllMaps => + [ + PaldeaFieldIndex.Paldea, + PaldeaFieldIndex.Kitakami, + PaldeaFieldIndex.Terarium, + ]; public void DumpTo(string path, IReadOnlyList specNamesInternal, IReadOnlyList moveNames, Dictionary placeNameMap, @@ -40,9 +44,11 @@ public class EncounterDumperSV var alEncPoints = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/point_data/point_data/encount_data_atlantis.bin")); var su1EncPoints = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/point_data/point_data/encount_data_su1.bin")); var su2EncPoints = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/point_data/point_data/encount_data_su2.bin")); + //var lcEncPoints = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/point_data/point_data/encount_data_lc.bin")); var pokeDataMain = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/pokedata/pokedata/pokedata_array.bin")); var pokeDataSu1 = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/pokedata/pokedata_su1/pokedata_su1_array.bin")); var pokeDataSu2 = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/pokedata/pokedata_su2/pokedata_su2_array.bin")); + //var pokeDataLc = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/data/encount/pokedata/pokedata_lc/pokedata_lc_array.bfbs")); var db = new LocationDatabase(); @@ -51,6 +57,7 @@ public class EncounterDumperSV var pointAtlantis = ReformatPoints(alEncPoints); var pointSu1 = ReformatPoints(su1EncPoints); var pointSu2 = ReformatPoints(su2EncPoints); + //var lc = ReformatPoints(lcEncPoints); // Process all field indices ProcessAreas(PaldeaFieldIndex.Paldea); @@ -93,11 +100,11 @@ public class EncounterDumperSV foreach (var (game, gamePoints) in new[] { ("sl", fsym.scarletPoints), ("vl", fsym.violetPoints) }) { using var gw = File.CreateText(Path.Combine(path, $"titan_fixed_{game}.txt")); - foreach (var fieldIndex in new[] { PaldeaFieldIndex.Paldea, PaldeaFieldIndex.Kitakami, PaldeaFieldIndex.Terarium }) + foreach (var fieldIndex in AllMaps) { var areaNames = scene.AreaNames[(int)fieldIndex]; var areas = scene.AreaInfos[(int)fieldIndex]; - var atlantis = scene.IsAtlantis[(int)fieldIndex]; + var atlantis = scene.PaldeaType[(int)fieldIndex]; var allPoints = gamePoints[(int)fieldIndex]; if (fieldIndex is PaldeaFieldIndex.Kitakami) @@ -111,6 +118,8 @@ public class EncounterDumperSV { var entry = fsymData.Table[i]; var tableKey = entry.TableKey; + if (tableKey.StartsWith("su2_w23d10_")) + continue; // handle later, manually var points = allPoints.FindAll(p => p.TableKey == tableKey); if (points.Count == 0) continue; @@ -125,7 +134,7 @@ bool FindArea(AreaType type) for (var x = areaNames.Count - 1; x >= 0; x--) { var areaName = areaNames[x]; - if (atlantis[areaName]) + if (atlantis[areaName] != PaldeaPointPivot.Overworld) continue; var areaInfo = areas[areaName]; @@ -156,61 +165,10 @@ bool FindArea(AreaType type) return false; } - var locs = appearAreas.Select(a => placeNameMap[a.PlaceName].Index).Distinct().ToList(); - - gw.WriteLine("==="); - gw.WriteLine($"{tableKey} - {i}"); - gw.WriteLine("==="); - gw.WriteLine(" PokeData:"); - var pd = entry.Symbol; - gw.WriteLine($" Species: {specNamesInternal[(int)pd.DevId]}"); - gw.WriteLine($" Form: {pd.FormId}"); - gw.Write($" Level: {pd.Level}"); - foreach (var adj in appearAreas.Select(a => a.Adjust).Where(lv => lv != 0).Distinct().Order()) - { - gw.Write($", {pd.Level + adj}"); - } - gw.WriteLine(); - gw.WriteLine($" Sex: {Humanize(pd.Sex)}"); - gw.WriteLine($" Shiny: {Humanize(pd.RareType)}"); - - var talentStr = pd.TalentType switch - { - TalentType.RANDOM => "Random", - TalentType.V_NUM => $"{pd.TalentVNum} Perfect", - TalentType.VALUE => $"{pd.TalentValue.HP}/{pd.TalentValue.ATK}/{pd.TalentValue.DEF}/{pd.TalentValue.SPA}/{pd.TalentValue.SPD}/{pd.TalentValue.SPE}", - _ => "Invalid", - }; - gw.WriteLine($" IVs: {talentStr}"); - gw.WriteLine($" Ability: {Humanize(pd.TokuseiIndex)}"); - switch (pd.WazaType) - { - case WazaType.DEFAULT: - gw.WriteLine(" Moves: Random"); - break; - case WazaType.MANUAL: - gw.WriteLine($" Moves: {moveNames[(int)pd.Waza1.WazaId]}/{moveNames[(int)pd.Waza2.WazaId]}/{moveNames[(int)pd.Waza3.WazaId]}/{moveNames[(int)pd.Waza4.WazaId]}"); - break; - } - - gw.WriteLine($" Scale: {Humanize(pd.ScaleType, pd.ScaleValue)}"); - gw.WriteLine($" GemType: {(int)pd.GemType}"); - - gw.WriteLine(" Points:"); - foreach (var point in points) - { - gw.WriteLine($" - ({point.Position.X}, {point.Position.Y}, {point.Position.Z})"); - } - - gw.WriteLine(" Areas:"); - foreach (var area in appearAreas) - { - var loc = area.PlaceName; - (string name, int index) = placeNameMap[loc]; - gw.WriteLine($" - {area.PlaceName} - {loc} - {name} ({index})"); - } + WriteFixedSpawn(specNamesInternal, moveNames, placeNameMap, gw, tableKey, i, entry, appearAreas, points); // Serialize + var locs = appearAreas.Select(a => placeNameMap[a.PlaceName].Index).Distinct().ToList(); if (locs.Count == 0) continue; if (BannedFixedSpawnNames.Contains(entry.TableKey)) @@ -226,7 +184,7 @@ bool FindArea(AreaType type) for (var a = 0; a < allNames.Count; a++) { var areaName = allNames[a]; - if (atlantis[areaName]) + if (atlantis[areaName] != PaldeaPointPivot.Overworld) continue; var areaInfo = allInfos[areaName]; @@ -255,10 +213,21 @@ bool FindArea(AreaType type) locationIDs.Sort(); WriteFixedSymbol(serialized, entry, locationIDs); - WriteFixedSymbol(serialized, entry, locationIDs, adjust); + if (adjust != 0) + WriteFixedSymbol(serialized, entry, locationIDs, adjust); } } } + + var underDepths = Array.FindIndex(fsymData.Table.ToArray(), x => x.TableKey == "su2_w23d10_01"); + for (int i = underDepths; i < underDepths + 23; i++) + { + var entry = fsymData.Table[i]; + var tableKey = entry.TableKey; + var appearAreas = new List { new("PLACENAME_a_w23_d10_01", "a_w23_d10_subarea", 0, new()) }; + WriteFixedSpawn(specNamesInternal, moveNames, placeNameMap, gw, tableKey, i, entry, appearAreas, []); + WriteFixedSymbol(serialized, entry, new[] { 196 }); + } } // Gimmighoul only in Paldea @@ -268,7 +237,7 @@ bool FindArea(AreaType type) var areas = new List(); foreach (var areaName in scene.AreaNames[(int)PaldeaFieldIndex.Paldea]) { - if (scene.IsAtlantis[(int)PaldeaFieldIndex.Paldea][areaName]) + if (scene.PaldeaType[(int)PaldeaFieldIndex.Paldea][areaName] != PaldeaPointPivot.Overworld) continue; var areaInfo = scene.AreaInfos[(int)PaldeaFieldIndex.Paldea][areaName]; @@ -346,9 +315,14 @@ bool FindArea(AreaType type) return; // HELPERS - LocationPointDetail[] GetPoints(PaldeaFieldIndex fieldIndex, bool isAtlantis) => fieldIndex switch + LocationPointDetail[] GetPoints(PaldeaFieldIndex fieldIndex, PaldeaPointPivot type) => fieldIndex switch { - PaldeaFieldIndex.Paldea => isAtlantis ? pointAtlantis : pointMain, + PaldeaFieldIndex.Paldea => type switch + { + PaldeaPointPivot.Overworld => pointMain, + PaldeaPointPivot.AreaZero => pointAtlantis, + _ => throw new ArgumentException($"Could not handle {type}"), + }, PaldeaFieldIndex.Kitakami => pointSu1, PaldeaFieldIndex.Terarium => pointSu2, _ => throw new ArgumentException($"Could not handle {fieldIndex}"), @@ -374,11 +348,10 @@ void ProcessAreas(PaldeaFieldIndex fieldIndex) // Fill the point lists for each area, then spawn everything into those points. var areaNames = scene.AreaNames[(int)fieldIndex]; var areas = scene.AreaInfos[(int)fieldIndex]; - var atlantis = scene.IsAtlantis[(int)fieldIndex]; + var types = scene.PaldeaType[(int)fieldIndex]; for (var i = areaNames.Count - 1; i >= 0; i--) { var areaName = areaNames[i]; - var areaInfo = areas[areaName]; // Determine potential spawners if (!scene.TryGetContainsCheck(fieldIndex, areaName, out var collider)) @@ -387,6 +360,7 @@ void ProcessAreas(PaldeaFieldIndex fieldIndex) continue; } + var areaInfo = areas[areaName]; // Areas without a location name can't be reversed into location ID. if (!TryGetPlaceName(ref areaName, areaInfo, collider, placeNameMap, areas, scene, fieldIndex, out var placeName)) continue; @@ -397,7 +371,8 @@ void ProcessAreas(PaldeaFieldIndex fieldIndex) if (areaInfo.Tag is AreaTag.NG_Encount or AreaTag.NG_All) continue; - var points = GetPoints(fieldIndex, atlantis[areaName]); + var type = types[areaName]; + var points = GetPoints(fieldIndex, type); storage.LoadPoints(points, collider, areaInfo.ActualMinLevel, areaInfo.ActualMaxLevel, areaInfo.AdjustEncLv); storage.GetEncounters(GetPokeData(fieldIndex), scene); } @@ -458,6 +433,62 @@ void ProcessAreas(PaldeaFieldIndex fieldIndex) } } + private static void WriteFixedSpawn(IReadOnlyList specNamesInternal, IReadOnlyList moveNames, Dictionary placeNameMap, + StreamWriter gw, string tableKey, int i, FixedSymbolTable entry, List appearAreas, List points) + { + gw.WriteLine("==="); + gw.WriteLine($"{tableKey} - {i}"); + gw.WriteLine("==="); + gw.WriteLine(" PokeData:"); + var pd = entry.Symbol; + gw.WriteLine($" Species: {specNamesInternal[(int)pd.DevId]}"); + gw.WriteLine($" Form: {pd.FormId}"); + gw.Write($" Level: {pd.Level}"); + foreach (var adj in appearAreas.Select(a => a.Adjust).Where(lv => lv != 0).Distinct().Order()) + { + gw.Write($", {pd.Level + adj}"); + } + gw.WriteLine(); + gw.WriteLine($" Sex: {Humanize(pd.Sex)}"); + gw.WriteLine($" Shiny: {Humanize(pd.RareType)}"); + + var talentStr = pd.TalentType switch + { + TalentType.RANDOM => "Random", + TalentType.V_NUM => $"{pd.TalentVNum} Perfect", + TalentType.VALUE => $"{pd.TalentValue.HP}/{pd.TalentValue.ATK}/{pd.TalentValue.DEF}/{pd.TalentValue.SPA}/{pd.TalentValue.SPD}/{pd.TalentValue.SPE}", + _ => "Invalid", + }; + gw.WriteLine($" IVs: {talentStr}"); + gw.WriteLine($" Ability: {Humanize(pd.TokuseiIndex)}"); + switch (pd.WazaType) + { + case WazaType.DEFAULT: + gw.WriteLine(" Moves: Random"); + break; + case WazaType.MANUAL: + gw.WriteLine($" Moves: {moveNames[(int)pd.Waza1.WazaId]}/{moveNames[(int)pd.Waza2.WazaId]}/{moveNames[(int)pd.Waza3.WazaId]}/{moveNames[(int)pd.Waza4.WazaId]}"); + break; + } + + gw.WriteLine($" Scale: {Humanize(pd.ScaleType, pd.ScaleValue)}"); + gw.WriteLine($" GemType: {(int)pd.GemType}"); + + gw.WriteLine(" Points:"); + foreach (var point in points) + { + gw.WriteLine($" - ({point.Position.X}, {point.Position.Y}, {point.Position.Z})"); + } + + gw.WriteLine(" Areas:"); + foreach (var area in appearAreas) + { + var loc = area.PlaceName; + (string name, int index) = placeNameMap[loc]; + gw.WriteLine($" - {area.PlaceName} - {loc} - {name} ({index})"); + } + } + private static bool TryGetBleedArea(IContainsV3f collider, List appearAreas, PaldeaSceneModel scene, PaldeaFieldIndex fieldIndex, out AppearTuple bledFrom) { foreach (var a in appearAreas) @@ -644,7 +675,7 @@ private static void WriteFixedSymbol(ICollection exist, FixedSymbolTable bw.Write(form); bw.Write((byte)(enc.Level + adjustLevel)); - bw.Write((byte)enc.TalentVNum); + bw.Write(enc.TalentType == TalentType.RANDOM ? (byte)0 : (byte)enc.TalentVNum); bw.Write((byte)enc.GemType); bw.Write((byte)(enc.Sex - 1)); bw.Write((byte)0); // reserved diff --git a/pkNX.WinForms/Dumping/SV/PaldeaFixedSymbolModel.cs b/pkNX.WinForms/Dumping/SV/PaldeaFixedSymbolModel.cs index d99e8f2e..91ba963b 100644 --- a/pkNX.WinForms/Dumping/SV/PaldeaFixedSymbolModel.cs +++ b/pkNX.WinForms/Dumping/SV/PaldeaFixedSymbolModel.cs @@ -50,6 +50,15 @@ public PaldeaFixedSymbolModel(IFileInternal ROM) scarletPoints[(int)PaldeaFieldIndex.Terarium].AddRange(GetObjectTemplateSymbolPoints(b0)); violetPoints[(int)PaldeaFieldIndex.Terarium].AddRange(GetObjectTemplateSymbolPoints(b1)); + + // Underdepths + //var u0Data = ROM.GetPackedFile("world/scene/parts/field/room/a_w23_d10/a_w23_d10_event/a_w23_d10_fixed_placement_symbol_/a_w23_d10_fixed_placement_symbol_0.trscn"); + //var u1Data = ROM.GetPackedFile("world/scene/parts/field/room/a_w23_d10/a_w23_d10_event/a_w23_d10_fixed_placement_symbol_/a_w23_d10_fixed_placement_symbol_1.trscn"); + //var u0 = FlatBufferConverter.DeserializeFrom(u0Data); + //var u1 = FlatBufferConverter.DeserializeFrom(u1Data); + // + //scarletPoints[(int)PaldeaFieldIndex.Paldea].AddRange(GetObjectTemplateSymbolPoints(u0)); + //violetPoints[(int)PaldeaFieldIndex.Paldea].AddRange(GetObjectTemplateSymbolPoints(u1)); } private static string[] GetTableGetKeys(GemSymbolLotteryTable entry) diff --git a/pkNX.WinForms/Dumping/SV/PaldeaSceneModel.cs b/pkNX.WinForms/Dumping/SV/PaldeaSceneModel.cs index 5a4600b9..619ed8b0 100644 --- a/pkNX.WinForms/Dumping/SV/PaldeaSceneModel.cs +++ b/pkNX.WinForms/Dumping/SV/PaldeaSceneModel.cs @@ -9,13 +9,19 @@ namespace pkNX.Structures.FlatBuffers; +public enum PaldeaPointPivot +{ + Overworld, + AreaZero, +} + public class PaldeaSceneModel { - public List[] AreaNames { get; } = { new(), new(), new() }; - public Dictionary[] AreaInfos { get; } = { new(), new(), new() }; - public Dictionary[] AreaCollisionTrees { get; } = { new(), new(), new() }; - public Dictionary[] AreaCollisionBoxes { get; } = { new(), new(), new() }; - public Dictionary[] IsAtlantis { get; } = { new(), new(), new() }; + public List[] AreaNames { get; } = [new(), new(), new()]; + public Dictionary[] AreaInfos { get; } = [new(), new(), new()]; + public Dictionary[] AreaCollisionTrees { get; } = [new(), new(), new()]; + public Dictionary[] AreaCollisionBoxes { get; } = [new(), new(), new()]; + public Dictionary[] PaldeaType { get; } = [new(), new(), new()]; public PaldeaSceneModel(IFileInternal ROM, PaldeaFieldModel field) { @@ -24,7 +30,8 @@ public PaldeaSceneModel(IFileInternal ROM, PaldeaFieldModel field) Debug.Assert(area_collision.ObjectTemplateName == "resident_area_collision"); // NOTE: Safe to only use _0 because _1 is identical. - var a_w23_field_area_col = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/scene/parts/field/room/a_w23_field/a_w23_field_area_col_/a_w23_field_area_col_0.trscn")); + var a0 = ROM.GetPackedFile("world/scene/parts/field/room/a_w23_field/a_w23_field_area_col_/a_w23_field_area_col_0.trscn"); + var a_w23_field_area_col = FlatBufferConverter.DeserializeFrom(a0); Debug.Assert(a_w23_field_area_col.ObjectTemplateName == "a_w23_field_area_col"); foreach (var obj in area_collision.Objects.Concat(a_w23_field_area_col.Objects)) @@ -35,17 +42,18 @@ public PaldeaSceneModel(IFileInternal ROM, PaldeaFieldModel field) Debug.Assert(area_collision_su1.ObjectTemplateName == "resident_area_collision"); foreach (var obj in area_collision_su1.Objects) - AddIfAppropriate(ROM, field, PaldeaFieldIndex.Kitakami, new List(), obj); + AddIfAppropriate(ROM, field, PaldeaFieldIndex.Kitakami, [], obj); // NOTE: Safe to only use _0 because _1 is identical. var area_collision_su2 = FlatBufferConverter.DeserializeFrom(ROM.GetPackedFile("world/scene/parts/field/main/field_2/field_main/resident_event/resident_area_collision_/resident_area_collision_0.trscn")); Debug.Assert(area_collision_su2.ObjectTemplateName == "resident_area_collision"); foreach (var obj in area_collision_su2.Objects) - AddIfAppropriate(ROM, field, PaldeaFieldIndex.Terarium, new List(), obj); + AddIfAppropriate(ROM, field, PaldeaFieldIndex.Terarium, [], obj); } - private void AddIfAppropriate(IFileInternal ROM, PaldeaFieldModel field, PaldeaFieldIndex index, IList atlantis, TrinitySceneObjectTemplateEntry obj) + private void AddIfAppropriate(IFileInternal ROM, PaldeaFieldModel field, PaldeaFieldIndex index, + IList a0, TrinitySceneObjectTemplateEntry obj) { if (!(obj.SubObjects.Count > 0 && obj.SubObjects[0].Type == "trinity_CollisionComponent")) return; @@ -54,7 +62,7 @@ private void AddIfAppropriate(IFileInternal ROM, PaldeaFieldModel field, PaldeaF var tcom = FlatBufferConverter.DeserializeFrom(inner); var collision = tcom.Component.CollisionComponent.Shape; - var isAtlantisObj = atlantis.Contains(obj); + var isAtlantisObj = GetPaldeaType(a0, obj); switch (obj.Type) { case "trinity_ObjectTemplate": @@ -66,14 +74,14 @@ private void AddIfAppropriate(IFileInternal ROM, PaldeaFieldModel field, PaldeaF Debug.Assert(sceneObject.ObjectName == sObj.ObjectTemplateExtra); AddSceneObject(index, sObj.ObjectTemplateName, sceneObject, collision, field, ROM); - IsAtlantis[(int)index][sObj.ObjectTemplateName] = isAtlantisObj; + PaldeaType[(int)index][sObj.ObjectTemplateName] = isAtlantisObj; break; } case "trinity_SceneObject": { var sceneObject = FlatBufferConverter.DeserializeFrom(obj.Data); AddSceneObject(index, sceneObject.ObjectName, sceneObject, collision, field, ROM); - IsAtlantis[(int)index][sceneObject.ObjectName] = isAtlantisObj; + PaldeaType[(int)index][sceneObject.ObjectName] = isAtlantisObj; break; } // ReSharper disable once RedundantEmptySwitchSection @@ -85,6 +93,13 @@ private void AddIfAppropriate(IFileInternal ROM, PaldeaFieldModel field, PaldeaF } } + private PaldeaPointPivot GetPaldeaType(IList a0, TrinitySceneObjectTemplateEntry obj) + { + if (a0.Contains(obj)) + return PaldeaPointPivot.AreaZero; + return PaldeaPointPivot.Overworld; + } + private void AddSceneObject(PaldeaFieldIndex index, string name, TrinitySceneObject sceneObject, CollisionUnion shape, PaldeaFieldModel field, IFileInternal ROM) { AreaNames[(int)index].Add(name); diff --git a/pkNX.WinForms/pkNX.WinForms.csproj b/pkNX.WinForms/pkNX.WinForms.csproj index 1097983b..27e37ac0 100644 --- a/pkNX.WinForms/pkNX.WinForms.csproj +++ b/pkNX.WinForms/pkNX.WinForms.csproj @@ -46,7 +46,7 @@ - +