diff --git a/pkNX.WinForms/Dumping/GameDumperSV.cs b/pkNX.WinForms/Dumping/GameDumperSV.cs index 7a548986..f7286f01 100644 --- a/pkNX.WinForms/Dumping/GameDumperSV.cs +++ b/pkNX.WinForms/Dumping/GameDumperSV.cs @@ -1121,6 +1121,6 @@ public void DumpArchives() public void DumpDistributionRaids(string path) { - TeraRaidRipper.DumpDistributionRaids(path); + TeraRaidRipper.DumpDistributionRaids(ROM, path); } } diff --git a/pkNX.WinForms/Dumping/TeraRaidRipper.cs b/pkNX.WinForms/Dumping/TeraRaidRipper.cs index 1010b4f8..1ef47425 100644 --- a/pkNX.WinForms/Dumping/TeraRaidRipper.cs +++ b/pkNX.WinForms/Dumping/TeraRaidRipper.cs @@ -5,13 +5,16 @@ using System.IO; using System.Linq; using pkNX.Containers; +using pkNX.Game; using pkNX.Structures; using pkNX.Structures.FlatBuffers; namespace pkNX.WinForms; -public static class TeraRaidRipper +public class TeraRaidRipper { + private readonly GameManagerSV ROM; + public TeraRaidRipper(GameManagerSV rom) => ROM = rom; public static void DumpRaids(IFileInternal ROM, IReadOnlyList internalRaidFiles, string outPath) { var list = new List(); @@ -115,14 +118,14 @@ public short GetVioletRandMinViolet() new [] { 3, 4, 5, 6, 7 }, }; - public static void DumpDistributionRaids(string path) + public static void DumpDistributionRaids(IFileInternal ROM, string path) { var dirs = Directory.GetDirectories(path).OrderBy(z => z); var type2 = new List(); var type3 = new List(); foreach (var dir in dirs) - DumpDistributionRaids(dir, type2, type3); + DumpDistributionRaids(ROM, dir, type2, type3); DumpPicklePath(type2, path, "encounter_dist_paldea.pkl"); DumpPicklePath(type3, path, "encounter_might_paldea.pkl"); @@ -139,7 +142,7 @@ private static void DumpPicklePath(List list, string path, string pp) File.WriteAllBytes(pathPickle, ordered.SelectMany(z => z).ToArray()); } - private static void DumpDistributionRaids(string path, List type2, List type3) + private static void DumpDistributionRaids(IFileInternal ROM, string path, List type2, List type3) { var dataEncounters = GetDistributionContents(Path.Combine(path, "raid_enemy_array"), out int indexEncounters); var dataDrop = GetDistributionContents(Path.Combine(path, "fixed_reward_item_array"), out int indexDrop); @@ -184,7 +187,7 @@ private static void DumpDistributionRaids(string path, List type2, List< } var dirDistText = Path.Combine(path, "parse"); - ExportParse(dirDistText, tableEncounters, tableDrops, tableBonus, tablePriority); + ExportParse(ROM, dirDistText, tableEncounters, tableDrops, tableBonus, tablePriority); } private static void AddToList(IReadOnlyCollection table, List list, RaidSerializationFormat format) @@ -255,7 +258,7 @@ private static void AddToList(IReadOnlyCollection table, list.Add(bin); } - private static void ExportParse(string dir, + private static void ExportParse(IFileInternal ROM, string dir, DeliveryRaidEnemyTableArray tableEncounters, DeliveryRaidFixedRewardItemArray tableDrops, DeliveryRaidLotteryRewardItemArray tableBonus, @@ -292,6 +295,7 @@ private static void AddToList(IReadOnlyCollection table, DumpJson(tableDrops, dir, "drop"); DumpJson(tableBonus, dir, "bonus"); DumpJson(tablePriority, dir, "priority"); + DumpPretty(ROM, tableEncounters, tableDrops, tableBonus, dir); } private static void DumpJson(object flat, string dir, string name) @@ -308,4 +312,182 @@ private static byte[] GetDistributionContents(string path, out int index) index = 0; // todo return File.ReadAllBytes(path); } + + private static string[] GetCommonText(IFileInternal ROM, string name, string lang, TextConfig cfg) + { + var data = ROM.GetPackedFile($"message/dat/{lang}/common/{name}.dat"); + return new TextFile(data, cfg).Lines; + } + + private static void DumpPretty(IFileInternal ROM, DeliveryRaidEnemyTableArray tableEncounters, DeliveryRaidFixedRewardItemArray tableDrops, DeliveryRaidLotteryRewardItemArray tableBonus, string dir) + { + var cfg = new TextConfig(GameVersion.SV); + var lines = new List(); + + var bosses = tableEncounters.Table.Select(z => z.RaidEnemyInfo.BossPokePara); + var dropTable = tableEncounters.Table.Select(z => z.RaidEnemyInfo.DropTableFix); + var bonusTable = tableEncounters.Table.Select(z => z.RaidEnemyInfo.DropTableRandom); + var ident = tableEncounters.Table[0].RaidEnemyInfo.No; + + var species = GetCommonText(ROM, "monsname", "English", cfg); + var items = GetCommonText(ROM, "itemname", "English", cfg); + var moves = GetCommonText(ROM, "wazaname", "English", cfg); + + lines.Add($"Event Raid Identifier: {ident}"); + + foreach (var entry in tableEncounters.Table) + { + var boss = entry.RaidEnemyInfo.BossPokePara; + var extra = entry.RaidEnemyInfo.BossDesc; + var nameDrop = entry.RaidEnemyInfo.DropTableFix; + var nameBonus = entry.RaidEnemyInfo.DropTableRandom; + + if (boss.DevId == DevID.DEV_NULL) + continue; + + var version = entry.RaidEnemyInfo.RomVer switch + { + RaidRomType.TYPE_A => "Scarlet", + RaidRomType.TYPE_B => "Violet", + _ => string.Empty, + }; + + var gem = boss.GemType switch + { + GemType.DEFAULT => "Default", + GemType.RANDOM => "Random", + _ => $"{(PKHeX.Core.MoveType)boss.GemType - 2}", + }; + + var ability = boss.Tokusei switch + { + TokuseiType.SET_1 => "1 Only", + TokuseiType.SET_2 => "2 Only", + TokuseiType.SET_3 => "Hidden Only", + TokuseiType.RANDOM_12 => "1/2", + _ => "1/2/Hidden", + }; + + var shiny = boss.RareType switch + { + RareType.RARE => "Always", + RareType.NO_RARE => "Never", + _ => string.Empty, + }; + + var nature = boss.Seikaku == SeikakuType.DEFAULT ? "Random" : $"{(PKHeX.Core.Nature)(int)entry.RaidEnemyInfo.BossPokePara.Seikaku - 1}"; + + var talent = boss.TalentValue; + var iv = boss.TalentType switch + { + TalentType.VALUE when talent.HP == 31 && talent.ATK == 31 && talent.DEF == 31 && talent.SPA == 31 && talent.SPD == 31 && talent.SPE == 31 => "6 Flawless", + TalentType.VALUE => $"{boss.TalentValue.HP}/{boss.TalentValue.ATK}/{boss.TalentValue.DEF}/{boss.TalentValue.SPA}/{boss.TalentValue.SPD}/{boss.TalentValue.SPE}", + _ => $"{boss.TalentVnum} Flawless", + }; + + var form = boss.FormId == 0 ? string.Empty : $"-{entry.RaidEnemyInfo.BossPokePara.FormId}"; + + lines.Add($"{entry.RaidEnemyInfo.Difficulty}-Star {species[(int)entry.RaidEnemyInfo.BossPokePara.DevId]}{form}"); + if (entry.RaidEnemyInfo.RomVer != RaidRomType.BOTH) + lines.Add($"\tVersion: {version}"); + + lines.Add($"\tTera Type: {gem}"); + lines.Add($"\tCapture Level: {entry.RaidEnemyInfo.CaptureLv}"); + lines.Add($"\tAbility: {ability}"); + lines.Add($"\tNature: {nature}"); + lines.Add($"\tIVs: {iv}"); + + if (entry.RaidEnemyInfo.BossPokePara.RareType != RareType.DEFAULT) + lines.Add($"\tShiny: {shiny}"); + + lines.Add($"\t\tMoves:"); + lines.Add($"\t\t\t- {moves[(int)boss.Waza1.WazaId]}"); + if ((int)boss.Waza2.WazaId != 0) lines.Add($"\t\t\t- {moves[(int)boss.Waza2.WazaId]}"); + if ((int)boss.Waza2.WazaId != 0) lines.Add($"\t\t\t- {moves[(int)boss.Waza3.WazaId]}"); + if ((int)boss.Waza2.WazaId != 0) lines.Add($"\t\t\t- {moves[(int)boss.Waza4.WazaId]}"); + + lines.Add($"\t\tExtra Moves:"); + if ((int)extra.ExtraAction1.Wazano == 0 && (int)extra.ExtraAction2.Wazano == 0 && (int)extra.ExtraAction3.Wazano == 0 && (int)extra.ExtraAction4.Wazano == 0 && (int)extra.ExtraAction5.Wazano == 0 && (int)extra.ExtraAction6.Wazano == 0) + lines.Add("\t\t\tNone!"); + + else + { + if ((int)extra.ExtraAction1.Wazano != 0) lines.Add($"\t\t\t- {moves[(int)extra.ExtraAction1.Wazano]}"); + if ((int)extra.ExtraAction2.Wazano != 0) lines.Add($"\t\t\t- {moves[(int)extra.ExtraAction2.Wazano]}"); + if ((int)extra.ExtraAction3.Wazano != 0) lines.Add($"\t\t\t- {moves[(int)extra.ExtraAction3.Wazano]}"); + if ((int)extra.ExtraAction4.Wazano != 0) lines.Add($"\t\t\t- {moves[(int)extra.ExtraAction4.Wazano]}"); + if ((int)extra.ExtraAction5.Wazano != 0) lines.Add($"\t\t\t- {moves[(int)extra.ExtraAction5.Wazano]}"); + if ((int)extra.ExtraAction6.Wazano != 0) lines.Add($"\t\t\t- {moves[(int)extra.ExtraAction6.Wazano]}"); + } + + lines.Add("\t\tItem Drops:"); + + foreach (var item in tableDrops.Table.Where(z => z.TableName == nameDrop)) + { + for (int i = 0; i <= 14; i++) + { + if (entry.RaidEnemyInfo.DropTableFix != item.TableName) + continue; + + var drop = item.GetReward(i); + var one = (int)item.GetReward(i).SubjectType == 3 ? " (Only Once)" : string.Empty; + + string GetItemName(int item) + { + bool isTM = (int)drop.ItemID is (>= 328 and <= 419) or (>= 618 and <= 620) or (>= 690 and <= 693) or (>= 2160 and <= 2231); + var tm = PKHeX.Core.LearnSource9SV.TM_SV.ToArray(); + + if (isTM) // append move name to TM + { + if ((int)drop.ItemID is >= 328 and <= 419) + return $"{items[(int)drop.ItemID]} {moves[tm[(int)drop.ItemID]]}"; + if ((int)drop.ItemID is 618 or 619 or 620) + return $"{items[(int)drop.ItemID]} {moves[tm[100 + (int)drop.ItemID - 618]]}"; + if ((int)drop.ItemID is 690 or 691 or 692 or 693) + return $"{items[(int)drop.ItemID]} {moves[tm[100 + (int)drop.ItemID - 690]]}"; + + return $"{items[(int)drop.ItemID]} {moves[tm[100 + (int)drop.ItemID - 2160]]}"; + } + + return $"{items[(int)drop.ItemID]}"; + } + + if ((int)drop.Category == 1) // Material + lines.Add($"\t\t\t{drop.Num,2} × Crafting Material{one}"); + + if ((int)drop.Category == 2) // Tera Shard + lines.Add($"\t\t\t{drop.Num,2} × Tera Shard{one}"); + + if (drop.ItemID != 0) + lines.Add($"\t\t\t{drop.Num,2} × {GetItemName((int)drop.ItemID)}{one}"); + } + } + + lines.Add("\t\tBonus Drops:"); + + foreach (var item in tableBonus.Table.Where(z => z.TableName == nameBonus)) + { + float totalRate = 0; + for (int i = 0; i <= 29; i++) + totalRate += item.GetRewardItem(i).Rate; + + for (int i = 0; i <= 29; i++) + { + if (entry.RaidEnemyInfo.DropTableRandom != item.TableName) + continue; + + var drop = item.GetRewardItem(i); + if (drop.ItemID != 0) + { + float rate = (float)(Math.Round((float)((item.GetRewardItem(i).Rate / totalRate) * 100f), 2)); + lines.Add($"\t\t\t{(float)rate,5}% {drop.Num,2} × {items[(int)drop.ItemID]}"); + } + } + } + + lines.Add(""); + } + + File.WriteAllLines(Path.Combine(dir, $"pretty_{ident}.txt"), lines); + } }