public SAV3(byte[] data = null, GameVersion versionOverride = GameVersion.Any) { Data = data == null ? new byte[SaveUtil.SIZE_G3RAW] : (byte[])data.Clone(); BAK = (byte[])Data.Clone(); Exportable = !Data.SequenceEqual(new byte[Data.Length]); if (data == null) { Version = GameVersion.FRLG; } else if (versionOverride != GameVersion.Any) { Version = versionOverride; } else { Version = SaveUtil.getIsG3SAV(Data); } if (Version == GameVersion.Invalid) { return; } int[] BlockOrder1 = new int[14]; for (int i = 0; i < 14; i++) { BlockOrder1[i] = BitConverter.ToInt16(Data, i * 0x1000 + 0xFF4); } int zeroBlock1 = Array.IndexOf(BlockOrder1, 0); if (data.Length > SaveUtil.SIZE_G3RAWHALF) { int[] BlockOrder2 = new int[14]; for (int i = 0; i < 14; i++) { BlockOrder2[i] = BitConverter.ToInt16(Data, 0xE000 + i * 0x1000 + 0xFF4); } int zeroBlock2 = Array.IndexOf(BlockOrder2, 0); if (zeroBlock2 < 0) { ActiveSAV = 0; } else if (zeroBlock1 < 0) { ActiveSAV = 1; } else { ActiveSAV = BitConverter.ToUInt32(Data, zeroBlock1 * 0x1000 + 0xFFC) > BitConverter.ToUInt32(Data, zeroBlock2 * 0x1000 + 0xEFFC) ? 0 : 1; } BlockOrder = ActiveSAV == 0 ? BlockOrder1 : BlockOrder2; } else { ActiveSAV = 0; BlockOrder = BlockOrder1; } BlockOfs = new int[14]; for (int i = 0; i < 14; i++) { BlockOfs[i] = Array.IndexOf(BlockOrder, i) * 0x1000 + ABO; } // Set up PC data buffer beyond end of save file. Box = Data.Length; Array.Resize(ref Data, Data.Length + SIZE_RESERVED); // More than enough empty space. // Copy chunk to the allocated location for (int i = 5; i < 14; i++) { int blockIndex = Array.IndexOf(BlockOrder, i); if (blockIndex == -1) // block empty { continue; } Array.Copy(Data, blockIndex * 0x1000 + ABO, Data, Box + (i - 5) * 0xF80, chunkLength[i]); } switch (Version) { case GameVersion.RS: LegalKeyItems = Legal.Pouch_Key_RS; OFS_PouchHeldItem = BlockOfs[1] + 0x0560; OFS_PouchKeyItem = BlockOfs[1] + 0x05B0; OFS_PouchBalls = BlockOfs[1] + 0x0600; OFS_PouchTMHM = BlockOfs[1] + 0x0640; OFS_PouchBerry = BlockOfs[1] + 0x0740; Personal = PersonalTable.RS; break; case GameVersion.FRLG: LegalKeyItems = Legal.Pouch_Key_FRLG; OFS_PouchHeldItem = BlockOfs[1] + 0x0310; OFS_PouchKeyItem = BlockOfs[1] + 0x03B8; OFS_PouchBalls = BlockOfs[1] + 0x0430; OFS_PouchTMHM = BlockOfs[1] + 0x0464; OFS_PouchBerry = BlockOfs[1] + 0x054C; Personal = PersonalTable.FR; break; case GameVersion.E: LegalKeyItems = Legal.Pouch_Key_E; OFS_PouchHeldItem = BlockOfs[1] + 0x0560; OFS_PouchKeyItem = BlockOfs[1] + 0x05D8; OFS_PouchBalls = BlockOfs[1] + 0x0650; OFS_PouchTMHM = BlockOfs[1] + 0x0690; OFS_PouchBerry = BlockOfs[1] + 0x0790; Personal = PersonalTable.E; break; } LegalItems = Legal.Pouch_Items_RS; LegalBalls = Legal.Pouch_Ball_RS; LegalTMHMs = Legal.Pouch_TMHM_RS; LegalBerries = Legal.Pouch_Berries_RS; HeldItems = Legal.HeldItems_RS; if (!Exportable) { resetBoxes(); } }
public SAV2(byte[] data = null) { Data = data == null ? new byte[SaveUtil.SIZE_G2RAW_U] : (byte[])data.Clone(); BAK = (byte[])Data.Clone(); Exportable = !Data.SequenceEqual(new byte[Data.Length]); Version = data == null ? GameVersion.GSC : SaveUtil.getIsG2SAV(Data); if (Version == GameVersion.Invalid) { return; } Japanese = SaveUtil.getIsG2SAVJ(Data) != GameVersion.Invalid; if (Japanese && Data.Length < SaveUtil.SIZE_G2RAW_J) { Array.Resize(ref Data, SaveUtil.SIZE_G2RAW_J); } Box = Data.Length; Array.Resize(ref Data, Data.Length + SIZE_RESERVED); Party = getPartyOffset(0); Personal = Version == GameVersion.GS ? PersonalTable.GS : PersonalTable.C; getSAVOffsets(); LegalItems = Legal.Pouch_Items_GSC; LegalBalls = Legal.Pouch_Ball_GSC; LegalKeyItems = Version == GameVersion.C ? Legal.Pouch_Key_C : Legal.Pouch_Key_GS; LegalTMHMs = Legal.Pouch_TMHM_GSC; HeldItems = Legal.HeldItems_GSC; // Stash boxes after the save file's end. byte[] TempBox = new byte[SIZE_STOREDBOX]; for (int i = 0; i < BoxCount; i++) { if (i < (Japanese ? 6 : 7)) { Array.Copy(Data, 0x4000 + i * (TempBox.Length + 2), TempBox, 0, TempBox.Length); } else { Array.Copy(Data, 0x6000 + (i - (Japanese ? 6 : 7)) * (TempBox.Length + 2), TempBox, 0, TempBox.Length); } PokemonList2 PL2 = new PokemonList2(TempBox, Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese); for (int j = 0; j < PL2.Pokemon.Length; j++) { if (j < PL2.Count) { byte[] pkDat = new PokemonList2(PL2[j]).GetBytes(); pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED); } else { byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)]; pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED); } } } Array.Copy(Data, CurrentBoxOffset, TempBox, 0, TempBox.Length); PokemonList2 curBoxPL = new PokemonList2(TempBox, Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese); for (int i = 0; i < curBoxPL.Pokemon.Length; i++) { if (i < curBoxPL.Count) { byte[] pkDat = new PokemonList2(curBoxPL[i]).GetBytes(); pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED); } else { byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)]; pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED); } } byte[] TempParty = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Party, Japanese)]; Array.Copy(Data, PartyOffset, TempParty, 0, TempParty.Length); PokemonList2 partyList = new PokemonList2(TempParty, PokemonList2.CapacityType.Party, Japanese); for (int i = 0; i < partyList.Pokemon.Length; i++) { if (i < partyList.Count) { byte[] pkDat = new PokemonList2(partyList[i]).GetBytes(); pkDat.CopyTo(Data, getPartyOffset(i)); } else { byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)]; pkDat.CopyTo(Data, getPartyOffset(i)); } } // Daycare currently undocumented for all Gen II games. // Enable Pokedex editing PokeDex = 0; if (!Exportable) { resetBoxes(); } }
public MysteryGift Clone() { byte[] data = (byte[])Data.Clone(); return(getMysteryGift(data)); }
public override byte[] Encrypt() { return((byte[])Data.Clone()); }
public SAV3XD(byte[] data = null) { Data = data == null ? new byte[SaveUtil.SIZE_G3XD] : (byte[])data.Clone(); BAK = (byte[])Data.Clone(); Exportable = !Data.SequenceEqual(new byte[Data.Length]); if (SaveUtil.getIsG3XDSAV(Data) != GameVersion.XD) { return; } OriginalData = (byte[])Data.Clone(); // Scan all 3 save slots for the highest counter for (int i = 0; i < SLOT_COUNT; i++) { int slotOffset = SLOT_START + i * SLOT_SIZE; int SaveCounter = BigEndian.ToInt32(Data, slotOffset + 4); if (SaveCounter <= SaveCount) { continue; } SaveCount = SaveCounter; SaveIndex = i; } // Decrypt most recent save slot { byte[] slot = new byte[SLOT_SIZE]; int slotOffset = SLOT_START + SaveIndex * SLOT_SIZE; Array.Copy(Data, slotOffset, slot, 0, slot.Length); ushort[] keys = new ushort[4]; for (int i = 0; i < keys.Length; i++) { keys[i] = BigEndian.ToUInt16(slot, 8 + i * 2); } // Decrypt Slot Data = SaveUtil.DecryptGC(slot, 0x00010, 0x27FD8, keys); } // Get Offset Info ushort[] subLength = new ushort[16]; for (int i = 0; i < 16; i++) { subLength[i] = BigEndian.ToUInt16(Data, 0x20 + 2 * i); subOffsets[i] = BigEndian.ToUInt16(Data, 0x40 + 4 * i) | BigEndian.ToUInt16(Data, 0x40 + 4 * i + 2) << 16; } // Offsets are displaced by the 0xA8 savedata region Trainer1 = subOffsets[1] + 0xA8; Party = Trainer1 + 0x30; Box = subOffsets[2] + 0xA8; Daycare = subOffsets[4] + 0xA8; Memo = subOffsets[5] + 0xA8; Shadow = subOffsets[7] + 0xA8; // Purifier = subOffsets[14] + 0xA8; StrategyMemo = new StrategyMemo(Data, Memo, xd: true); ShadowInfo = new ShadowInfoTableXD(Data.Skip(Shadow).Take(subLength[7]).ToArray()); OFS_PouchHeldItem = Trainer1 + 0x4C8; OFS_PouchKeyItem = Trainer1 + 0x540; OFS_PouchBalls = Trainer1 + 0x5EC; OFS_PouchTMHM = Trainer1 + 0x62C; OFS_PouchBerry = Trainer1 + 0x72C; OFS_PouchCologne = Trainer1 + 0x7E4; OFS_PouchDisc = Trainer1 + 0x7F0; LegalItems = Legal.Pouch_Items_XD; LegalKeyItems = Legal.Pouch_Key_XD; LegalBalls = Legal.Pouch_Ball_RS; LegalTMHMs = Legal.Pouch_TM_RS; // not HMs LegalBerries = Legal.Pouch_Berries_RS; LegalCologne = Legal.Pouch_Cologne_CXD; LegalDisc = Legal.Pouch_Disc_XD; Personal = PersonalTable.RS; HeldItems = Legal.HeldItems_XD; if (!Exportable) { resetBoxes(); } // Since PartyCount is not stored in the save file, // Count up how many party slots are active. for (int i = 0; i < 6; i++) { if (getPartySlot(getPartyOffset(i)).Species != 0) { PartyCount++; } } }