From 1ef510bcf052937e5ef7b0e9c4abbbd4f2f6e9b5 Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 27 Nov 2019 22:29:13 -0800 Subject: [PATCH] Add split file encounter dumping, weather groups Diferent weather allows for different Mark values (ribbon), and only Symbol encounters can wander into adjacent maps Need to have separate exports with appropriate metadata add nest dumper I forgot to push before working on slot dump v2 --- .../Gen8/FlatWild/EncounterTableUtil.cs | 127 ++++++++++++++++++ pkNX.WinForms/Dumping/GameDumperSWSH.cs | 28 ++++ 2 files changed, 155 insertions(+) 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 };