using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; using static DSPRE.RomInfo; namespace DSPRE.ROMFiles { /* ---------------------- WILD POKéMON DATA STRUCTURE (DPPt):---------------------------- 0x0 // byte: Walking encounter rate 0x4 // byte: Level of 0x2 // ushort: Matrix number 0x4 // ushort: Script file number 0x6 // ushort: Level script file number 0x8 // ushort: Text Archive number 0xA // ushort: Day music track number 0xC // ushort: Night music track number 0xE // ushort: Wild Pokemon file number 0x10 // ushort: Event file number * Diamond/Pearl: 0x12 // ushort: Index of map name in Text Archive #382 (US version) * Platinum: 0x12 // byte: Index of map name in Text Archive #382 (US version) 0x13 // byte: Map name textbox type value 0x14 // byte: Weather value 0x15 // byte: Camera value 0x16 // byte: Boolean flag: show name when entering map 0x17 // byte: Bitwise permission flags: ----------------- 1: Allow Fly ----------------- 2: ? ----------------- 3: ? ----------------- 4: Allow Bike usage ----------------- 5: ? ----------------- 6: ? ----------------- 7: Esc. Rope ----------------- 8: ? /* ---------------------- WILD POKéMON DATA STRUCTURE (HGSS):---------------------------- 0x0 // byte: Wild Pokemon file number 0x1 // byte: Area data value 0x2 // byte: ? 0x3 // byte: ? 0x4 // ushort: Matrix number 0x6 // ushort: Script file number 0x8 // ushort: Level script file 0xA // ushort: Text Archive number 0xC // ushort: Day music track number 0xE // ushort: Night music track number 0x10 // ushort: Event file number 0x12 // byte: Index of map name in Text Archive #382 (US version) 0x13 // byte: Map name textbox type value 0x14 // byte: Weather value 0x15 // byte: Camera value 0x16 // byte: Follow mode (for the Pokemon following hero) 0x17 // byte: Bitwise permission flags: ----------------- 1: Allow Fly ----------------- 2: ? ----------------- 3: ? ----------------- 4: Allow Bike usage ----------------- 5: ? ----------------- 6: ? ----------------- 7: Esc. Rope ----------------- 8: ? ----------------------------------------------------------------------------------*/ /// /// General class to store common wild Pokemon data across all Gen IV Pokemon NDS games /// public abstract class EncounterFile : RomFile { public const string msgFixed = " (already fixed)"; #region Fields (19) /* Encounter rates */ public byte goodRodRate { get; set; } public byte oldRodRate { get; set; } public byte superRodRate { get; set; } public byte surfRate { get; set; } public byte walkingRate { get; set; } /* Levels */ public byte[] goodRodMaxLevels = new byte[5]; public byte[] goodRodMinLevels = new byte[5]; public byte[] oldRodMaxLevels = new byte[5]; public byte[] oldRodMinLevels = new byte[5]; public byte[] walkingLevels = new byte[12]; public byte[] superRodMaxLevels = new byte[5]; public byte[] superRodMinLevels = new byte[5]; public byte[] surfMaxLevels = new byte[5]; public byte[] surfMinLevels = new byte[5]; /* Encounters */ public ushort[] goodRodPokemon = new ushort[5]; public ushort[] oldRodPokemon = new ushort[5]; public ushort[] superRodPokemon = new ushort[5]; public ushort[] surfPokemon = new ushort[5]; public ushort[] swarmPokemon { get; set; } #endregion #region Methods (1) public void SaveToFileDefaultDir(int IDtoReplace, bool showSuccessMessage = true) { SaveToFileDefaultDir(DirNames.encounters, IDtoReplace, showSuccessMessage); } public void ReportErrors(List errorList) { string fullError = "The following sections of this encounter file couldn't be read correctly: " + Environment.NewLine; string errorSections = ""; foreach (string elem in errorList) { errorSections += "- " + elem + Environment.NewLine; } fullError += errorSections; fullError += Environment.NewLine + "It is recommended that you check them before resaving."; if (errorSections.Contains(msgFixed)) { fullError += Environment.NewLine + "Fields marked as " + '\'' + msgFixed + '\'' + " have been repaired with a value of 0."; } MessageBox.Show(fullError, "Encounter File error", MessageBoxButtons.OK, MessageBoxIcon.Error); } #endregion } /// /// Class to store wild Pokemon data from Pokemon Diamond, Pearl and Platinum /// public class EncounterFileDPPt : EncounterFile { #region Fields (9) /* Field encounters */ public uint[] radarPokemon = new uint[4]; public uint[] walkingPokemon = new uint[12]; /* Time-specific encounters */ public uint[] morningPokemon = new uint[2]; public uint[] nightPokemon = new uint[2]; /* Dual slot exclusives */ public uint[] rubyPokemon = new uint[2]; public uint[] sapphirePokemon = new uint[2]; public uint[] emeraldPokemon = new uint[2]; public uint[] fireRedPokemon = new uint[2]; public uint[] leafGreenPokemon = new uint[2]; #endregion #region Constructors (1) public EncounterFileDPPt(Stream data) { using (BinaryReader reader = new BinaryReader(data)) { List fieldsWithErrors = new List(); /* Walking encounters */ try { walkingRate = (byte)reader.ReadInt32(); for (int i = 0; i < 12; i++) { walkingLevels[i] = (byte)reader.ReadUInt32(); walkingPokemon[i] = reader.ReadUInt32(); } } catch { fieldsWithErrors.Add("Regular encounters"); } /* Swarms */ swarmPokemon = new ushort[2]; for (int i = 0; i < 2; i++) { try { swarmPokemon[i] = (ushort)reader.ReadUInt32(); } catch (EndOfStreamException) { swarmPokemon[i] = 0x00; fieldsWithErrors.Add("Swarms" + ' ' + '[' + i + ']' + msgFixed); } } /* Time-specific encounters */ for (int i = 0; i < 2; i++) { try { morningPokemon[i] = reader.ReadUInt32(); } catch { morningPokemon[i] = 0x00; fieldsWithErrors.Add("Morning encounters" + ' ' + '[' + i + ']' + msgFixed); } } for (int i = 0; i < 2; i++) { try { nightPokemon[i] = reader.ReadUInt32(); } catch { nightPokemon[i] = 0x00; fieldsWithErrors.Add("Night encounters" + ' ' + '[' + i + ']' + msgFixed); } } /* Poké-Radar encounters */ for (int i = 0; i < 4; i++) { try { radarPokemon[i] = reader.ReadUInt32(); } catch { radarPokemon[i] = 0x00; fieldsWithErrors.Add("PokéRadar" + ' ' + '[' + i + ']' + msgFixed); } } reader.BaseStream.Position = 0xA4; /* Dual-slot encounters */ for (int i = 0; i < 2; i++) { try { rubyPokemon[i] = reader.ReadUInt32(); } catch { rubyPokemon[i] = 0x00; fieldsWithErrors.Add("Dual-Slot Ruby" + ' ' + '[' + i + ']' + msgFixed); } } for (int i = 0; i < 2; i++) { try { sapphirePokemon[i] = reader.ReadUInt32(); } catch { sapphirePokemon[i] = 0x00; fieldsWithErrors.Add("Dual-Slot Sapphire" + ' ' + '[' + i + ']' + msgFixed); } } for (int i = 0; i < 2; i++) { try { emeraldPokemon[i] = reader.ReadUInt32(); } catch { emeraldPokemon[i] = 0x00; fieldsWithErrors.Add("Dual-Slot Emerald" + ' ' + '[' + i + ']' + msgFixed); } } for (int i = 0; i < 2; i++) { try { fireRedPokemon[i] = reader.ReadUInt32(); } catch { fireRedPokemon[i] = 0x00; fieldsWithErrors.Add("Dual-Slot FireRed" + ' ' + '[' + i + ']' + msgFixed); } } for (int i = 0; i < 2; i++) { try { leafGreenPokemon[i] = reader.ReadUInt32(); } catch { leafGreenPokemon[i] = 0x00; fieldsWithErrors.Add("Dual-Slot LeafGreen" + ' ' + '[' + i + ']' + msgFixed); } } /* Surf encounters */ try { surfRate = (byte)reader.ReadInt32(); for (int i = 0; i < 5; i++) { surfMaxLevels[i] = reader.ReadByte(); surfMinLevels[i] = reader.ReadByte(); reader.BaseStream.Position += 0x2; surfPokemon[i] = (ushort)reader.ReadUInt32(); } } catch { fieldsWithErrors.Add("Surf"); } reader.BaseStream.Position = 0x124; /* Old Rod encounters */ try { oldRodRate = (byte)reader.ReadInt32(); for (int i = 0; i < 5; i++) { oldRodMaxLevels[i] = reader.ReadByte(); oldRodMinLevels[i] = reader.ReadByte(); reader.BaseStream.Position += 0x2; oldRodPokemon[i] = (ushort)reader.ReadUInt32(); } } catch { fieldsWithErrors.Add("Old Rod"); } /* Good Rod encounters */ try { goodRodRate = (byte)reader.ReadInt32(); for (int i = 0; i < 5; i++) { goodRodMaxLevels[i] = reader.ReadByte(); goodRodMinLevels[i] = reader.ReadByte(); reader.BaseStream.Position += 0x2; goodRodPokemon[i] = (ushort)reader.ReadUInt32(); } } catch { fieldsWithErrors.Add("Good Rod"); } /* Super Rod encounters */ try { superRodRate = (byte)reader.ReadInt32(); for (int i = 0; i < 5; i++) { superRodMaxLevels[i] = reader.ReadByte(); superRodMinLevels[i] = reader.ReadByte(); reader.BaseStream.Position += 0x2; superRodPokemon[i] = (ushort)reader.ReadUInt32(); } } catch { fieldsWithErrors.Add("Super Rod"); } if (fieldsWithErrors.Count > 0) { ReportErrors(fieldsWithErrors); } } } public EncounterFileDPPt(int ID) : this(new FileStream(RomInfo.gameDirs[DirNames.encounters].unpackedDir + "\\" + ID.ToString("D4"), FileMode.Open)) { } #endregion Constructors #region Methods (1) public override byte[] ToByteArray() { MemoryStream newData = new MemoryStream(); using (BinaryWriter writer = new BinaryWriter(newData)) { writer.Write((uint)walkingRate); /* Walking encounters */ for (int i = 0; i < 12; i++) { writer.Write((uint)walkingLevels[i]); writer.Write(walkingPokemon[i]); } /* Swarms */ for (int i = 0; i < 2; i++) { writer.Write((uint)swarmPokemon[i]); } /* Time-specific encounters */ for (int i = 0; i < 2; i++) { writer.Write(morningPokemon[i]); } for (int i = 0; i < 2; i++) { writer.Write(nightPokemon[i]); } /* Poké-Radar encounters */ for (int i = 0; i < 4; i++) { writer.Write(radarPokemon[i]); } writer.BaseStream.Position = 0xA4; /* Dual-slot encounters */ for (int i = 0; i < 2; i++) { writer.Write(rubyPokemon[i]); } for (int i = 0; i < 2; i++) { writer.Write(sapphirePokemon[i]); } for (int i = 0; i < 2; i++) { writer.Write(emeraldPokemon[i]); } for (int i = 0; i < 2; i++) { writer.Write(fireRedPokemon[i]); } for (int i = 0; i < 2; i++) { writer.Write(leafGreenPokemon[i]); } /* Surf encounters */ writer.Write((uint)surfRate); for (int i = 0; i < 5; i++) { writer.Write(surfMaxLevels[i]); writer.Write(surfMinLevels[i]); writer.BaseStream.Position += 0x2; writer.Write((uint)surfPokemon[i]); } writer.BaseStream.Position = 0x124; /* Old Rod encounters */ writer.Write((uint)oldRodRate); for (int i = 0; i < 5; i++) { writer.Write(oldRodMaxLevels[i]); writer.Write(oldRodMinLevels[i]); writer.BaseStream.Position += 0x2; writer.Write((uint)oldRodPokemon[i]); } /* Good Rod encounters */ writer.Write((uint)goodRodRate); for (int i = 0; i < 5; i++) { writer.Write(goodRodMaxLevels[i]); writer.Write(goodRodMinLevels[i]); writer.BaseStream.Position += 0x2; writer.Write((uint)goodRodPokemon[i]); } /* Super Rod encounters */ writer.Write((uint)superRodRate); for (int i = 0; i < 5; i++) { writer.Write(superRodMaxLevels[i]); writer.Write(superRodMinLevels[i]); writer.BaseStream.Position += 0x2; writer.Write((uint)superRodPokemon[i]); } } return newData.ToArray(); } public void SaveToFileExplorePath(string suggestedFileName, bool showSuccessMessage = true) { SaveToFileExplorePath("DPPt Encounter File", "enc", suggestedFileName, showSuccessMessage); } #endregion } /// /// Class to store wild Pokemon data from Pokemon HeartGold and SoulSilver /// public class EncounterFileHGSS : EncounterFile { #region Fields (9) public byte rockSmashRate; public ushort[] morningPokemon = new ushort[12]; public ushort[] dayPokemon = new ushort[12]; public ushort[] nightPokemon = new ushort[12]; public ushort[] hoennMusicPokemon = new ushort[2]; public ushort[] sinnohMusicPokemon = new ushort[2]; public ushort[] rockSmashPokemon = new ushort[2]; public byte[] rockSmashMinLevels = new byte[2]; public byte[] rockSmashMaxLevels = new byte[2]; #endregion #region Constructors (1) public EncounterFileHGSS(Stream data) { using (BinaryReader reader = new BinaryReader(data)) { List fieldsWithErrors = new List(); /* Encounter rates */ try { walkingRate = reader.ReadByte(); } catch { walkingRate = 0x00; fieldsWithErrors.Add("Regular encounters rate" + msgFixed); } try { surfRate = reader.ReadByte(); } catch { surfRate = 0x00; fieldsWithErrors.Add("Surf rate" + msgFixed); } try { rockSmashRate = reader.ReadByte(); } catch { rockSmashRate = 0x00; fieldsWithErrors.Add("Rock smash rate" + msgFixed); } try { oldRodRate = reader.ReadByte(); } catch { oldRodRate = 0x00; fieldsWithErrors.Add("Old Rod rate" + msgFixed); } try { goodRodRate = reader.ReadByte(); } catch { goodRodRate = 0x00; fieldsWithErrors.Add("Good Rod rate" + msgFixed); } try { superRodRate = reader.ReadByte(); } catch { superRodRate = 0x00; fieldsWithErrors.Add("Super Rod rate" + msgFixed); } reader.BaseStream.Position += 0x2; /* Walking encounters levels */ for (int i = 0; i < 12; i++) { try { walkingLevels[i] = reader.ReadByte(); } catch { walkingLevels[i] = 0x00; fieldsWithErrors.Add("Regular Encounters" + ' ' + '[' + i + ']' + msgFixed); } } /* Morning walking encounters */ for (int i = 0; i < 12; i++) { try { morningPokemon[i] = reader.ReadUInt16(); } catch { morningPokemon[i] = 0x00; fieldsWithErrors.Add("Morning Encounters" + ' ' + '[' + i + ']' + msgFixed); } } /* Day walking encounters */ for (int i = 0; i < 12; i++) { try { dayPokemon[i] = reader.ReadUInt16(); } catch { dayPokemon[i] = 0x00; fieldsWithErrors.Add("Day Encounters" + ' ' + '[' + i + ']' + msgFixed); } } /* Night walking encounters */ for (int i = 0; i < 12; i++) { try { nightPokemon[i] = reader.ReadUInt16(); } catch { nightPokemon[i] = 0x00; fieldsWithErrors.Add("Night Encounters" + ' ' + '[' + i + ']' + msgFixed); } } /* PokéGear music encounters */ for (int i = 0; i < 2; i++) { try { hoennMusicPokemon[i] = reader.ReadUInt16(); } catch { hoennMusicPokemon[i] = 0x00; fieldsWithErrors.Add("Hoenn Music Encounters" + ' ' + '[' + i + ']' + msgFixed); } } for (int i = 0; i < 2; i++) { try { sinnohMusicPokemon[i] = reader.ReadUInt16(); } catch { sinnohMusicPokemon[i] = 0x00; fieldsWithErrors.Add("Sinnoh Music Encounters" + ' ' + '[' + i + ']' + msgFixed); } } /* Surf encounters */ for (int i = 0; i < 5; i++) { surfMinLevels[i] = reader.ReadByte(); surfMaxLevels[i] = reader.ReadByte(); surfPokemon[i] = reader.ReadUInt16(); } /* Rock Smash encounters */ for (int i = 0; i < 2; i++) { rockSmashMinLevels[i] = reader.ReadByte(); rockSmashMaxLevels[i] = reader.ReadByte(); rockSmashPokemon[i] = reader.ReadUInt16(); } /* Old Rod encounters */ for (int i = 0; i < 5; i++) { oldRodMinLevels[i] = reader.ReadByte(); oldRodMaxLevels[i] = reader.ReadByte(); oldRodPokemon[i] = reader.ReadUInt16(); } /* Good Rod encounters */ for (int i = 0; i < 5; i++) { goodRodMinLevels[i] = reader.ReadByte(); goodRodMaxLevels[i] = reader.ReadByte(); goodRodPokemon[i] = reader.ReadUInt16(); } /* Super Rod encounters */ for (int i = 0; i < 5; i++) { superRodMinLevels[i] = reader.ReadByte(); superRodMaxLevels[i] = reader.ReadByte(); superRodPokemon[i] = reader.ReadUInt16(); } /* Swarm encounters */ swarmPokemon = new ushort[4]; for (int i = 0; i < 4; i++) { try { swarmPokemon[i] = reader.ReadUInt16(); } catch (EndOfStreamException) { swarmPokemon[i] = 0x00; fieldsWithErrors.Add("Swarms" + '[' + i + ']' + msgFixed); } } if (fieldsWithErrors.Count > 0) { ReportErrors(fieldsWithErrors); } } } public EncounterFileHGSS(int ID) : this(new FileStream(RomInfo.gameDirs[DirNames.encounters].unpackedDir + "\\" + ID.ToString("D4"), FileMode.Open)) { } #endregion #region Methods(1) public override byte[] ToByteArray() { MemoryStream newData = new MemoryStream(); using (BinaryWriter writer = new BinaryWriter(newData)) { /* Encounter rates */ writer.Write(walkingRate); writer.Write(surfRate); writer.Write(rockSmashRate); writer.Write(oldRodRate); writer.Write(goodRodRate); writer.Write(superRodRate); writer.BaseStream.Position += 0x2; /* Walking encounters levels */ for (int i = 0; i < 12; i++) { writer.Write(walkingLevels[i]); } /* Morning walking encounters */ for (int i = 0; i < 12; i++) { writer.Write(morningPokemon[i]); } /* Day walking encounters */ for (int i = 0; i < 12; i++) { writer.Write(dayPokemon[i]); } /* Night walking encounters */ for (int i = 0; i < 12; i++) { writer.Write(nightPokemon[i]); } /* PokéGear music encounters */ for (int i = 0; i < 2; i++) { writer.Write(hoennMusicPokemon[i]); } for (int i = 0; i < 2; i++) { writer.Write(sinnohMusicPokemon[i]); } /* Surf encounters */ for (int i = 0; i < 5; i++) { writer.Write(surfMinLevels[i]); writer.Write(surfMaxLevels[i]); writer.Write(surfPokemon[i]); } /* Rock Smash encounters */ for (int i = 0; i < 2; i++) { writer.Write(rockSmashMinLevels[i]); writer.Write(rockSmashMaxLevels[i]); writer.Write(rockSmashPokemon[i]); } /* Old Rod encounters */ for (int i = 0; i < 5; i++) { writer.Write(oldRodMinLevels[i]); writer.Write(oldRodMaxLevels[i]); writer.Write(oldRodPokemon[i]); } /* Good Rod encounters */ for (int i = 0; i < 5; i++) { writer.Write(goodRodMinLevels[i]); writer.Write(goodRodMaxLevels[i]); writer.Write(goodRodPokemon[i]); } /* Super Rod encounters */ for (int i = 0; i < 5; i++) { writer.Write(superRodMinLevels[i]); writer.Write(superRodMaxLevels[i]); writer.Write(superRodPokemon[i]); } /* Swarm encounters */ for (int i = 0; i < 4; i++) { writer.Write(swarmPokemon[i]); } } return newData.ToArray(); } public void SaveToFileExplorePath(string suggestedFileName, bool showSuccessMessage = true) { SaveToFileExplorePath("HGSS Encounter File", "enc", suggestedFileName, showSuccessMessage); } #endregion } }