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 @@
-
+