diff --git a/pkNX.Structures/Encounter/Gen8/FlatWild/EncounterTableUtil.cs b/pkNX.Structures/Encounter/Gen8/FlatWild/EncounterTableUtil.cs index 29f5c79b..0f148fb8 100644 --- a/pkNX.Structures/Encounter/Gen8/FlatWild/EncounterTableUtil.cs +++ b/pkNX.Structures/Encounter/Gen8/FlatWild/EncounterTableUtil.cs @@ -1,11 +1,138 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace pkNX.Structures { public static class EncounterTable8Util { + public static byte[][] GetBytes(IReadOnlyDictionary zone_loc, EncounterArchive8 t) + { + var result = new byte[t.EncounterTables.Length][]; + for (int i = 0; i < result.Length; i++) + { + var zone = t.EncounterTables[i]; + result[i] = GetZoneBytes(zone, zone_loc); + } + + return result; + } + + private static byte[] GetZoneBytes(EncounterTable8 zone, IReadOnlyDictionary zoneLoc) + { + byte locID = zoneLoc[zone.ZoneID]; + var list = new List(); + for (int i = 0; i < zone.SubTables.Length; i++) + { + var weather = (SWSHEncounterType)(1 << i); + var table = zone.SubTables[i]; + var min = table.LevelMin; + var max = table.LevelMax; + foreach (var s in table.Slots) + { + var s8 = new Slot8(s.Species, s.Form, min, max) {EncounterType = weather}; + var match = list.Find(z => z.Equals(s8)); + if (match == null) + list.Add(s8); + else + match.EncounterType |= weather; + } + } + + return SerializeSlot8(locID, list); + } + + private static byte[] SerializeSlot8(byte locID, IEnumerable list) + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + int ctr = 0; + bw.Write(locID); + bw.Write((byte) 0); // count tmp + var groups = list.GroupBy(z => (int) z.EncounterType | (z.Min << 16) | (z.Max << 24)); + foreach (var g in groups) + { + var slots = g.ToArray(); + var type = g.Key & 0xFFFF; + var min = (g.Key >> 16) & 0xFF; + var max = g.Key >> 24; + bw.Write((ushort) type); + bw.Write((byte) min); + bw.Write((byte) max); + bw.Write((byte) slots.Length); + bw.Write((byte) 0); + + foreach (var slot in slots) + bw.Write((ushort)(slot.Species | (slot.Form << 11))); + ctr += slots.Length; + } + + bw.BaseStream.Seek(1, SeekOrigin.Begin); + bw.Write((byte) ctr); + return ms.ToArray(); + } + + [Flags] + private enum SWSHEncounterType + { + None, + Normal = 1, + Overcast = 1 << 1, + Raining = 1 << 2, + Thunderstorm = 1 << 3, + Intense_Sun = 1 << 4, + Snowing = 1 << 5, + Snowstorm = 1 << 6, + Sandstorm = 1 << 7, + Heavy_Fog = 1 << 8, + Shaking_Trees = 1 << 9, + Fishing = 1 << 10, + }; + + private class Slot8 : IEquatable + { + public readonly int Species; + public readonly int Form; + public readonly int Min; + public readonly int Max; + public SWSHEncounterType EncounterType; + + public Slot8(int s, int f, int n, int x) + { + Species = s; + Form = f; + Min = n; + Max = x; + } + + public bool Equals(Slot8 other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return Species == other.Species && Form == other.Form && Min == other.Min && Max == other.Max; + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == GetType() && Equals((Slot8) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Species; + hashCode = (hashCode * 397) ^ Form; + hashCode = (hashCode * 397) ^ Min; + hashCode = (hashCode * 397) ^ Max; + return hashCode; + } + } + } + public static IEnumerable GetLines(EncounterArchive8 t, IReadOnlyDictionary zone_names, string[] subtable_names, string[] species) { for (var i = 0; i < t.EncounterTables.Length; i++) diff --git a/pkNX.WinForms/Dumping/GameDumperSWSH.cs b/pkNX.WinForms/Dumping/GameDumperSWSH.cs index 50c21285..4597fe5f 100644 --- a/pkNX.WinForms/Dumping/GameDumperSWSH.cs +++ b/pkNX.WinForms/Dumping/GameDumperSWSH.cs @@ -297,6 +297,11 @@ public void DumpWilds() File.WriteAllLines(GetPath("Encounters_Symbol_Sword.txt"), EncounterTable8Util.GetLines(encount_symbol_sw, zones, subtables, species)); File.WriteAllLines(GetPath("Encounters_Shield.txt"), EncounterTable8Util.GetLines(encount_sh, zones, subtables, species)); File.WriteAllLines(GetPath("Encounters_Symbol_Shield.txt"), EncounterTable8Util.GetLines(encount_symbol_sh, zones, subtables, species)); + + File.WriteAllBytes(GetPath("encounter_sw_hidden.pkl"), MiniUtil.PackMini(EncounterTable8Util.GetBytes(SWSHInfo.ZoneLocations, encount_sw), "sw")); + File.WriteAllBytes(GetPath("encounter_sh_hidden.pkl"), MiniUtil.PackMini(EncounterTable8Util.GetBytes(SWSHInfo.ZoneLocations, encount_sh), "sh")); + File.WriteAllBytes(GetPath("encounter_sw_symbol.pkl"), MiniUtil.PackMini(EncounterTable8Util.GetBytes(SWSHInfo.ZoneLocations, encount_symbol_sw), "sw")); + File.WriteAllBytes(GetPath("encounter_sh_symbol.pkl"), MiniUtil.PackMini(EncounterTable8Util.GetBytes(SWSHInfo.ZoneLocations, encount_symbol_sh), "sh")); } public void DumpNestEntries() @@ -457,6 +462,29 @@ public void DumpDistributionNestEntries(string path) var dist_sh = TableUtil.GetTable(dist_encounts.Tables.Where(z => z.GameVersion == 2).SelectMany(z => z.Entries)); File.WriteAllText(GetPath("nestDist_sw.txt"), dist_sw); File.WriteAllText(GetPath("nestDist_sh.txt"), dist_sh); + + string[][] nestHex = new string[2][]; + foreach (var game in new[] { 1, 2 }) + { + var tables = dist_encounts.Tables.Where(z => z.GameVersion == game).ToList(); + var encounters = tables.SelectMany((z, x) => z.GetSummary(speciesNames, x)).ToArray(); + + var path1 = GetPath($"nestHex{game}.txt"); + File.WriteAllLines(path1, encounters); + nestHex[game - 1] = encounters; + + var result = tables.Select(z => z.GetSummarySimple()); + var path2 = GetPath($"nestDistFormat_{game}.txt"); + File.WriteAllLines(path2, result); + } + + var common = nestHex[0].Intersect(nestHex[1]).Where(z => z.StartsWith(" ")).Distinct(); + var sword = nestHex[0].Where(z => !nestHex[1].Contains(z)).Distinct(); + var shield = nestHex[1].Where(z => !nestHex[0].Contains(z)).Distinct(); + + File.WriteAllLines(GetPath("hex_nestDistCommon.txt"), common); + File.WriteAllLines(GetPath("hex_nestDistSword.txt"), sword); + File.WriteAllLines(GetPath("hex_nestDistShield.txt"), shield); } private static readonly int[] LanguageIndexes = { 0, 2, 3, 4, 5, 6, 7, 8, 9 };