mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 14:44:24 +00:00
Split gen5-7 saves with inheritance (#2319)
refer to pull request comments for summary
This commit is contained in:
parent
84d1354e2f
commit
1b028198ad
93 changed files with 4317 additions and 3511 deletions
|
@ -15,6 +15,7 @@ namespace PKHeX.Core
|
|||
else
|
||||
sav.SetStoredSlot(pkm, slot.Offset);
|
||||
}
|
||||
|
||||
public static IReadOnlyList<PKM> GetAllPKM(this SaveFile sav)
|
||||
{
|
||||
var pkms = new List<PKM>();
|
||||
|
@ -139,8 +140,8 @@ namespace PKHeX.Core
|
|||
if (!all)
|
||||
return list;
|
||||
|
||||
for (int i = 0; i < SAV7.ResortCount; i++)
|
||||
list.Add(new StorageSlotOffset { Type = StorageSlotType.Resort, Offset = sav.GetResortSlotOffset(i) });
|
||||
for (int i = 0; i < ResortSave7.ResortCount; i++)
|
||||
list.Add(new StorageSlotOffset { Type = StorageSlotType.Resort, Offset = sav.ResortSave.GetResortSlotOffset(i) });
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using static PKHeX.Core.MessageStrings;
|
||||
|
@ -113,14 +112,11 @@ namespace PKHeX.Core
|
|||
|
||||
if (g is WC6 && g.CardID == 2048 && g.ItemID == 726) // Eon Ticket (OR/AS)
|
||||
{
|
||||
if (!SAV.ORAS)
|
||||
if (!(SAV is SAV6AO))
|
||||
{
|
||||
message = MsgMysteryGiftSlotSpecialReject;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the special recieved data
|
||||
BitConverter.GetBytes(WC6.EonTicketConst).CopyTo(SAV.Data, ((SAV6)SAV).EonTicket);
|
||||
}
|
||||
|
||||
message = null;
|
||||
|
|
|
@ -3,17 +3,35 @@ using System;
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Gen6+ Block Info
|
||||
/// Gen6+ Block Info (inside BEEF chunk)
|
||||
/// </summary>
|
||||
public sealed class BlockInfo3DS : BlockInfo
|
||||
public abstract class BlockInfo3DS : BlockInfo
|
||||
{
|
||||
public ushort Checksum;
|
||||
private int BlockInfoOffset;
|
||||
private readonly Func<byte[], int, int, ushort> CheckFunc;
|
||||
public BlockInfo3DS() { }
|
||||
private BlockInfo3DS(Func<byte[], int, int, ushort> func) => CheckFunc = func;
|
||||
private int ChecksumOffset => BlockInfoOffset + 6 + ((int)ID * 8);
|
||||
private ushort GetChecksum(byte[] data) => CheckFunc(data, Offset, Length);
|
||||
private readonly int BlockInfoOffset;
|
||||
|
||||
// ==chunk def== @ BlockInfoOffset
|
||||
// u64 timestamp1
|
||||
// u64 timestamp2
|
||||
// u8[4] BEEF magic
|
||||
// n*{blockInfo}, where n varies per sav type
|
||||
|
||||
// ==block info def==
|
||||
// u32 length
|
||||
// u16 id
|
||||
// u16 checksum
|
||||
|
||||
// when stored, each block size is rounded up to nearest 0x200, and the next chunk is immediately after
|
||||
|
||||
protected BlockInfo3DS(int bo, uint id, int ofs, int len)
|
||||
{
|
||||
BlockInfoOffset = bo;
|
||||
ID = id;
|
||||
Offset = ofs;
|
||||
Length = len;
|
||||
}
|
||||
|
||||
private int ChecksumOffset => BlockInfoOffset + 0x14 + ((int)ID * 8) + 6;
|
||||
protected abstract ushort GetChecksum(byte[] data);
|
||||
|
||||
protected override bool ChecksumValid(byte[] data)
|
||||
{
|
||||
|
@ -27,68 +45,54 @@ namespace PKHeX.Core
|
|||
ushort chk = GetChecksum(data);
|
||||
BitConverter.GetBytes(chk).CopyTo(data, ChecksumOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BlockInfo6 : BlockInfo3DS
|
||||
{
|
||||
public BlockInfo6(int bo, uint id, int ofs, int len) : base(bo, id, ofs, len) { }
|
||||
protected override ushort GetChecksum(byte[] data) => Checksums.CRC16_CCITT(data, Offset, Length);
|
||||
}
|
||||
|
||||
public sealed class BlockInfo7 : BlockInfo3DS
|
||||
{
|
||||
public BlockInfo7(int bo, uint id, int ofs, int len) : base(bo, id, ofs, len) { }
|
||||
protected override ushort GetChecksum(byte[] data) => Checksums.CRC16(data, Offset, Length);
|
||||
}
|
||||
|
||||
public sealed class BlockInfo7b : BlockInfo3DS
|
||||
{
|
||||
public BlockInfo7b(int bo, uint id, int ofs, int len) : base(bo, id, ofs, len) { }
|
||||
protected override ushort GetChecksum(byte[] data) => Checksums.CRC16NoInvert(data, Offset, Length);
|
||||
}
|
||||
|
||||
public static class BlockInfoBEEFUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="BlockInfo"/> table for the input <see cref="data"/>.
|
||||
/// Gets the <see cref="BlockInfo"/> for the input <see cref="data"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">Complete data array</param>
|
||||
/// <param name="blockInfoOffset">Offset the <see cref="BlockInfo"/> starts at.</param>
|
||||
/// <param name="CheckFunc">Checksum method for validating each block.</param>
|
||||
public static BlockInfo[] GetBlockInfoData(byte[] data, out int blockInfoOffset, Func<byte[], int, int, ushort> CheckFunc)
|
||||
public static void DumpComputedBlockInfo(byte[] data, int blockInfoOffset)
|
||||
{
|
||||
blockInfoOffset = data.Length - 0x200 + 0x10;
|
||||
if (BitConverter.ToUInt32(data, blockInfoOffset) != SaveUtil.BEEF)
|
||||
blockInfoOffset -= 0x200; // No savegames have more than 0x3D blocks, maybe in the future?
|
||||
int len = data.Length;
|
||||
return GetBlockInfo(data, ref blockInfoOffset, CheckFunc, len);
|
||||
}
|
||||
blockInfoOffset += 0x14;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="BlockInfo"/> table for the input <see cref="data"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">Complete data array</param>
|
||||
/// <param name="blockInfoOffset">Offset the <see cref="BlockInfo"/> starts at.</param>
|
||||
/// <param name="CheckFunc">Checksum method for validating each block.</param>
|
||||
/// <param name="dataLength"></param>
|
||||
public static BlockInfo[] GetBlockInfoData(byte[] data, ref int blockInfoOffset, Func<byte[], int, int, ushort> CheckFunc, int dataLength)
|
||||
{
|
||||
if (BitConverter.ToUInt32(data, blockInfoOffset) != SaveUtil.BEEF)
|
||||
blockInfoOffset -= 0x200; // No savegames have more than 0x3D blocks, maybe in the future?
|
||||
return GetBlockInfo(data, ref blockInfoOffset, CheckFunc, dataLength);
|
||||
}
|
||||
|
||||
private static BlockInfo[] GetBlockInfo(byte[] data, ref int blockInfoOffset, Func<byte[], int, int, ushort> CheckFunc, int dataLength)
|
||||
{
|
||||
int count = (dataLength - blockInfoOffset - 0x8) / 8;
|
||||
blockInfoOffset += 4;
|
||||
|
||||
var Blocks = new BlockInfo[count];
|
||||
int CurrentPosition = 0;
|
||||
for (int i = 0; i < Blocks.Length; i++)
|
||||
uint CurrentPosition = 0;
|
||||
for (int i = 0;; i++)
|
||||
{
|
||||
int ofs = i * 8;
|
||||
Blocks[i] = new BlockInfo3DS(CheckFunc)
|
||||
{
|
||||
Offset = CurrentPosition,
|
||||
Length = BitConverter.ToInt32(data, blockInfoOffset + ofs + 0),
|
||||
ID = BitConverter.ToUInt16(data, blockInfoOffset + ofs + 4),
|
||||
Checksum = BitConverter.ToUInt16(data, blockInfoOffset + ofs + 6),
|
||||
int ofs = blockInfoOffset + (i * 8);
|
||||
|
||||
BlockInfoOffset = blockInfoOffset
|
||||
};
|
||||
var Offset = CurrentPosition;
|
||||
var Length = BitConverter.ToUInt32(data, ofs + 0);
|
||||
if (Length == 0)
|
||||
break;
|
||||
var ID = BitConverter.ToUInt16(data, ofs + 4);
|
||||
// var Checksum = BitConverter.ToUInt16(data, ofs + 6);
|
||||
Console.WriteLine($"ID={ID}, Offset=0x{Offset:X5}, Length=0x{Length:X5}");
|
||||
|
||||
// Expand out to nearest 0x200
|
||||
var remainder = Blocks[i].Length & 0x1FF;
|
||||
CurrentPosition += remainder == 0 ? Blocks[i].Length : Blocks[i].Length + 0x200 - remainder;
|
||||
|
||||
if (Blocks[i].ID != 0 || i == 0)
|
||||
continue;
|
||||
count = i;
|
||||
break;
|
||||
var remainder = Length & 0x1FF;
|
||||
CurrentPosition += remainder == 0 ? Length : Length + 0x200 - remainder;
|
||||
}
|
||||
// Fix Final Array Lengths
|
||||
Array.Resize(ref Blocks, count);
|
||||
return Blocks;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,23 +18,30 @@ namespace PKHeX.Core
|
|||
return 1 <= gen && gen <= 2;
|
||||
}).ToArray();
|
||||
|
||||
public SAV1(byte[] data = null, GameVersion versionOverride = GameVersion.Any)
|
||||
public SAV1(GameVersion versionOverride = GameVersion.RBY, bool japanese = false) : base(SaveUtil.SIZE_G1RAW)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G1RAW];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
Version = versionOverride;
|
||||
Japanese = japanese;
|
||||
Offsets = Japanese ? SAV1Offsets.JPN : SAV1Offsets.INT;
|
||||
|
||||
if (versionOverride != GameVersion.Any)
|
||||
Version = versionOverride;
|
||||
else if(data == null)
|
||||
Version = GameVersion.RBY;
|
||||
else Version = SaveUtil.GetIsG1SAV(Data);
|
||||
Initialize(versionOverride);
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV1(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data)
|
||||
{
|
||||
Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG1SAV(data);
|
||||
if (Version == GameVersion.Invalid)
|
||||
return;
|
||||
|
||||
Japanese = SaveUtil.GetIsG1SAVJ(Data);
|
||||
Offsets = Japanese ? SAV1Offsets.JPN : SAV1Offsets.INT;
|
||||
|
||||
Initialize(versionOverride);
|
||||
}
|
||||
|
||||
private void Initialize(GameVersion versionOverride)
|
||||
{
|
||||
// see if RBY can be differentiated
|
||||
if (Starter != 0 && versionOverride != GameVersion.Any)
|
||||
Version = Yellow ? GameVersion.YW : GameVersion.RB;
|
||||
|
@ -102,9 +109,6 @@ namespace PKHeX.Core
|
|||
|
||||
// Enable Pokedex editing
|
||||
PokeDex = 0;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
private readonly SAV1Offsets Offsets;
|
||||
|
|
|
@ -20,34 +20,45 @@ namespace PKHeX.Core
|
|||
return 1 <= gen && gen <= 2;
|
||||
}).ToArray();
|
||||
|
||||
public SAV2(byte[] data = null, GameVersion versionOverride = GameVersion.Any)
|
||||
public SAV2(GameVersion versionOverride = GameVersion.C, LanguageID lang = LanguageID.English) : base(SaveUtil.SIZE_G2RAW_J)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G2RAW_U];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
|
||||
if (data == null)
|
||||
Version = GameVersion.C;
|
||||
else if (versionOverride != GameVersion.Any)
|
||||
Version = versionOverride;
|
||||
else
|
||||
Version = SaveUtil.GetIsG2SAV(Data);
|
||||
Version = versionOverride;
|
||||
switch (lang)
|
||||
{
|
||||
case LanguageID.Japanese:
|
||||
Japanese = true;
|
||||
break;
|
||||
case LanguageID.Korean:
|
||||
Korean = true;
|
||||
break;
|
||||
// otherwise, both false
|
||||
}
|
||||
Offsets = new SAV2Offsets(this);
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV2(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data)
|
||||
{
|
||||
Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG2SAV(Data);
|
||||
if (Version == GameVersion.Invalid)
|
||||
return;
|
||||
|
||||
Japanese = SaveUtil.GetIsG2SAVJ(Data) != GameVersion.Invalid;
|
||||
if (!Japanese)
|
||||
Korean = SaveUtil.GetIsG2SAVK(Data) != GameVersion.Invalid;
|
||||
|
||||
Offsets = new SAV2Offsets(this);
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Box = Data.Length;
|
||||
Array.Resize(ref Data, Data.Length + SIZE_RESERVED);
|
||||
Party = GetPartyOffset(0);
|
||||
|
||||
Personal = Version == GameVersion.GS ? PersonalTable.GS : PersonalTable.C;
|
||||
|
||||
Offsets = new SAV2Offsets(this);
|
||||
|
||||
LegalItems = Legal.Pouch_Items_GSC;
|
||||
LegalBalls = Legal.Pouch_Ball_GSC;
|
||||
LegalKeyItems = Version == GameVersion.C ? Legal.Pouch_Key_C : Legal.Pouch_Key_GS;
|
||||
|
@ -102,13 +113,17 @@ namespace PKHeX.Core
|
|||
{
|
||||
int offset = Offsets.Daycare;
|
||||
|
||||
DaycareFlags[0] = Data[offset]; offset++;
|
||||
DaycareFlags[0] = Data[offset];
|
||||
offset++;
|
||||
var pk1 = ReadPKMFromOffset(offset); // parent 1
|
||||
var daycare1 = new PokeList2(pk1);
|
||||
offset += (StringLength * 2) + 0x20; // nick/ot/pkm
|
||||
DaycareFlags[1] = Data[offset]; offset++;
|
||||
byte steps = Data[offset]; offset++;
|
||||
byte BreedMotherOrNonDitto = Data[offset]; offset++;
|
||||
DaycareFlags[1] = Data[offset];
|
||||
offset++;
|
||||
byte steps = Data[offset];
|
||||
offset++;
|
||||
byte BreedMotherOrNonDitto = Data[offset];
|
||||
offset++;
|
||||
var pk2 = ReadPKMFromOffset(offset); // parent 2
|
||||
var daycare2 = new PokeList2(pk2);
|
||||
offset += (StringLength * 2) + PKX.SIZE_2STORED; // nick/ot/pkm
|
||||
|
@ -126,9 +141,6 @@ namespace PKHeX.Core
|
|||
PokeDex = 0;
|
||||
EventFlag = Offsets.EventFlag;
|
||||
EventConst = Offsets.EventConst;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
private PK2 ReadPKMFromOffset(int offset)
|
||||
|
@ -405,7 +417,10 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs;
|
||||
private ushort[] LegalItems;
|
||||
private ushort[] LegalKeyItems;
|
||||
private ushort[] LegalBalls;
|
||||
private ushort[] LegalTMHMs;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
|
|
|
@ -67,12 +67,111 @@ namespace PKHeX.Core
|
|||
return chunkOffset;
|
||||
}
|
||||
|
||||
public SAV3(byte[] data = null, GameVersion versionOverride = GameVersion.Any)
|
||||
public SAV3(GameVersion version = GameVersion.FRLG, bool japanese = false) : base(SaveUtil.SIZE_G3RAW)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G3RAW];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
if (version == GameVersion.FR || version == GameVersion.LG)
|
||||
Version = GameVersion.FRLG;
|
||||
else if (version == GameVersion.R || version == GameVersion.LG)
|
||||
Version = GameVersion.RS;
|
||||
else
|
||||
Version = version;
|
||||
Personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS;
|
||||
Japanese = japanese;
|
||||
|
||||
LoadBlocks();
|
||||
// spoof block offsets
|
||||
BlockOfs = Enumerable.Range(0, BLOCK_COUNT).ToArray();
|
||||
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV3(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data)
|
||||
{
|
||||
LoadBlocks();
|
||||
Version = versionOverride != GameVersion.Any ? versionOverride : GetVersion(Data, BlockOfs[0]);
|
||||
Personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS;
|
||||
|
||||
// Japanese games are limited to 5 character OT names; any unused characters are 0xFF.
|
||||
// 5 for JP, 7 for INT. There's always 1 terminator, thus we can check 0x6-0x7 being 0xFFFF = INT
|
||||
// OT name is stored at the top of the first block.
|
||||
Japanese = BitConverter.ToInt16(Data, BlockOfs[0] + 0x6) == 0;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
// 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 < BLOCK_COUNT; i++)
|
||||
{
|
||||
int blockIndex = Array.IndexOf(BlockOrder, i);
|
||||
if (blockIndex == -1) // block empty
|
||||
continue;
|
||||
Array.Copy(Data, (blockIndex * SIZE_BLOCK) + ABO, Data, Box + ((i - 5) * 0xF80), chunkLength[i]);
|
||||
}
|
||||
|
||||
PokeDex = BlockOfs[0] + 0x18;
|
||||
switch (Version)
|
||||
{
|
||||
case GameVersion.RS:
|
||||
LegalKeyItems = Legal.Pouch_Key_RS;
|
||||
OFS_PCItem = BlockOfs[1] + 0x0498;
|
||||
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;
|
||||
SeenFlagOffsets = new[] {PokeDex + 0x44, BlockOfs[1] + 0x938, BlockOfs[4] + 0xC0C};
|
||||
EventFlag = BlockOfs[2] + 0x2A0;
|
||||
EventConst = EventFlag + (EventFlagMax / 8);
|
||||
Daycare = BlockOfs[4] + 0x11C;
|
||||
break;
|
||||
case GameVersion.E:
|
||||
LegalKeyItems = Legal.Pouch_Key_E;
|
||||
OFS_PCItem = BlockOfs[1] + 0x0498;
|
||||
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;
|
||||
SeenFlagOffsets = new[] {PokeDex + 0x44, BlockOfs[1] + 0x988, BlockOfs[4] + 0xCA4};
|
||||
EventFlag = BlockOfs[2] + 0x2F0;
|
||||
EventConst = EventFlag + (EventFlagMax / 8);
|
||||
Daycare = BlockOfs[4] + 0x1B0;
|
||||
break;
|
||||
case GameVersion.FRLG:
|
||||
LegalKeyItems = Legal.Pouch_Key_FRLG;
|
||||
OFS_PCItem = BlockOfs[1] + 0x0298;
|
||||
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;
|
||||
SeenFlagOffsets = new[] {PokeDex + 0x44, BlockOfs[1] + 0x5F8, BlockOfs[4] + 0xB98};
|
||||
EventFlag = BlockOfs[1] + 0xEE0;
|
||||
EventConst = BlockOfs[2] + 0x80;
|
||||
Daycare = BlockOfs[4] + 0x100;
|
||||
break;
|
||||
}
|
||||
|
||||
LoadEReaderBerryData();
|
||||
LegalItems = Legal.Pouch_Items_RS;
|
||||
LegalBalls = Legal.Pouch_Ball_RS;
|
||||
LegalTMHMs = Legal.Pouch_TMHM_RS;
|
||||
LegalBerries = Legal.Pouch_Berries_RS;
|
||||
HeldItems = Legal.HeldItems_RS;
|
||||
|
||||
// Sanity Check SeenFlagOffsets -- early saves may not have block 4 initialized yet
|
||||
SeenFlagOffsets = SeenFlagOffsets?.Where(z => z >= 0).ToArray();
|
||||
}
|
||||
|
||||
private void LoadBlocks()
|
||||
{
|
||||
int[] BlockOrder1 = GetBlockOrder(0);
|
||||
if (Data.Length > SaveUtil.SIZE_G3RAWHALF)
|
||||
{
|
||||
|
@ -92,97 +191,6 @@ namespace PKHeX.Core
|
|||
int index = Array.IndexOf(BlockOrder, i);
|
||||
BlockOfs[i] = index < 0 ? int.MinValue : (index * SIZE_BLOCK) + ABO;
|
||||
}
|
||||
|
||||
if (versionOverride != GameVersion.Any)
|
||||
Version = versionOverride;
|
||||
else if (data == null)
|
||||
Version = GameVersion.FRLG;
|
||||
else
|
||||
Version = GetVersion(Data, BlockOfs[0]);
|
||||
|
||||
Personal = SaveUtil.GetG3Personal(Version);
|
||||
if (data == null) // spoof block offsets
|
||||
{
|
||||
BlockOfs = Enumerable.Range(0, BLOCK_COUNT).ToArray();
|
||||
if (Version == GameVersion.FR || Version == GameVersion.LG)
|
||||
Version = GameVersion.FRLG;
|
||||
else if (Version == GameVersion.R || Version == GameVersion.LG)
|
||||
Version = GameVersion.RS;
|
||||
}
|
||||
|
||||
// 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 < BLOCK_COUNT; i++)
|
||||
{
|
||||
int blockIndex = Array.IndexOf(BlockOrder, i);
|
||||
if (blockIndex == -1) // block empty
|
||||
continue;
|
||||
Array.Copy(Data, (blockIndex * SIZE_BLOCK) + ABO, Data, Box + ((i - 5) * 0xF80), chunkLength[i]);
|
||||
}
|
||||
|
||||
// Japanese games are limited to 5 character OT names; any unused characters are 0xFF.
|
||||
// 5 for JP, 7 for INT. There's always 1 terminator, thus we can check 0x6-0x7 being 0xFFFF = INT
|
||||
// OT name is stored at the top of the first block.
|
||||
Japanese = BitConverter.ToInt16(Data, BlockOfs[0] + 0x6) == 0 && Exportable;
|
||||
|
||||
PokeDex = BlockOfs[0] + 0x18;
|
||||
switch (Version)
|
||||
{
|
||||
case GameVersion.RS:
|
||||
LegalKeyItems = Legal.Pouch_Key_RS;
|
||||
OFS_PCItem = BlockOfs[1] + 0x0498;
|
||||
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;
|
||||
SeenFlagOffsets = new[] { PokeDex + 0x44, BlockOfs[1] + 0x938, BlockOfs[4] + 0xC0C };
|
||||
EventFlag = BlockOfs[2] + 0x2A0;
|
||||
EventConst = EventFlag + (EventFlagMax / 8);
|
||||
Daycare = BlockOfs[4] + 0x11C;
|
||||
break;
|
||||
case GameVersion.E:
|
||||
LegalKeyItems = Legal.Pouch_Key_E;
|
||||
OFS_PCItem = BlockOfs[1] + 0x0498;
|
||||
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;
|
||||
SeenFlagOffsets = new[] { PokeDex + 0x44, BlockOfs[1] + 0x988, BlockOfs[4] + 0xCA4 };
|
||||
EventFlag = BlockOfs[2] + 0x2F0;
|
||||
EventConst = EventFlag + (EventFlagMax / 8);
|
||||
Daycare = BlockOfs[4] + 0x1B0;
|
||||
break;
|
||||
case GameVersion.FRLG:
|
||||
LegalKeyItems = Legal.Pouch_Key_FRLG;
|
||||
OFS_PCItem = BlockOfs[1] + 0x0298;
|
||||
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;
|
||||
SeenFlagOffsets = new[] { PokeDex + 0x44, BlockOfs[1] + 0x5F8, BlockOfs[4] + 0xB98 };
|
||||
EventFlag = BlockOfs[1] + 0xEE0;
|
||||
EventConst = BlockOfs[2] + 0x80;
|
||||
Daycare = BlockOfs[4] + 0x100;
|
||||
break;
|
||||
}
|
||||
LoadEReaderBerryData();
|
||||
LegalItems = Legal.Pouch_Items_RS;
|
||||
LegalBalls = Legal.Pouch_Ball_RS;
|
||||
LegalTMHMs = Legal.Pouch_TMHM_RS;
|
||||
LegalBerries = Legal.Pouch_Berries_RS;
|
||||
HeldItems = Legal.HeldItems_RS;
|
||||
|
||||
// Sanity Check SeenFlagOffsets -- early saves may not have block 4 initialized yet
|
||||
SeenFlagOffsets = SeenFlagOffsets?.Where(z => z >= 0).ToArray();
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
private int[] GetBlockOrder(int ofs)
|
||||
|
@ -244,10 +252,10 @@ namespace PKHeX.Core
|
|||
return result;
|
||||
}
|
||||
|
||||
private readonly int ActiveSAV;
|
||||
private int ActiveSAV;
|
||||
private int ABO => ActiveSAV*SIZE_BLOCK*0xE;
|
||||
private readonly int[] BlockOrder;
|
||||
private readonly int[] BlockOfs;
|
||||
private int[] BlockOrder;
|
||||
private int[] BlockOfs;
|
||||
public int GetBlockOffset(int block) => BlockOfs[block];
|
||||
|
||||
// Configuration
|
||||
|
@ -584,7 +592,11 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries;
|
||||
private ushort[] LegalItems;
|
||||
private ushort[] LegalKeyItems;
|
||||
private ushort[] LegalBalls;
|
||||
private ushort[] LegalTMHMs;
|
||||
private ushort[] LegalBerries;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
|
@ -719,7 +731,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
|
||||
// Pokédex
|
||||
private readonly int[] SeenFlagOffsets;
|
||||
private int[] SeenFlagOffsets;
|
||||
|
||||
protected override void SetDex(PKM pkm)
|
||||
{
|
||||
|
|
|
@ -29,25 +29,34 @@ namespace PKHeX.Core
|
|||
|
||||
private int SaveCount = -1;
|
||||
private int SaveIndex = -1;
|
||||
private readonly StrategyMemo StrategyMemo;
|
||||
private StrategyMemo StrategyMemo;
|
||||
public int MaxShadowID => 0x80; // 128
|
||||
private readonly int Memo;
|
||||
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries, LegalCologne;
|
||||
private readonly int OFS_PouchCologne;
|
||||
private int Memo;
|
||||
private ushort[] LegalItems;
|
||||
private ushort[] LegalKeyItems;
|
||||
private ushort[] LegalBalls;
|
||||
private ushort[] LegalTMHMs;
|
||||
private ushort[] LegalBerries;
|
||||
private ushort[] LegalCologne;
|
||||
private int OFS_PouchCologne;
|
||||
public SAV3Colosseum(byte[] data, SAV3GCMemoryCard MC) : this(data) { this.MC = MC; BAK = MC.Data; }
|
||||
|
||||
public SAV3Colosseum(byte[] data = null)
|
||||
public SAV3Colosseum() : base(SaveUtil.SIZE_G3COLO)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G3COLO];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV3Colosseum(byte[] data) : base(data)
|
||||
{
|
||||
InitializeData();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Personal = PersonalTable.RS;
|
||||
HeldItems = Legal.HeldItems_COLO;
|
||||
|
||||
if (SaveUtil.GetIsG3COLOSAV(Data) == GameVersion.COLO)
|
||||
InitializeData();
|
||||
|
||||
Trainer1 = 0x00078;
|
||||
Party = 0x000A8;
|
||||
OFS_PouchHeldItem = 0x007F8;
|
||||
|
@ -60,7 +69,7 @@ namespace PKHeX.Core
|
|||
Box = 0x00B90;
|
||||
Daycare = 0x08170;
|
||||
Memo = 0x082B0;
|
||||
StrategyMemo = new StrategyMemo(Data, Memo, xd:false);
|
||||
StrategyMemo = new StrategyMemo(Data, Memo, xd: false);
|
||||
|
||||
LegalItems = Legal.Pouch_Items_COLO;
|
||||
LegalKeyItems = Legal.Pouch_Key_COLO;
|
||||
|
@ -69,9 +78,6 @@ namespace PKHeX.Core
|
|||
LegalBerries = Legal.Pouch_Berries_RS;
|
||||
LegalCologne = Legal.Pouch_Cologne_COLO;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
|
||||
// Since PartyCount is not stored in the save file,
|
||||
// Count up how many party slots are active.
|
||||
for (int i = 0; i < 6; i++)
|
||||
|
|
|
@ -16,16 +16,28 @@ namespace PKHeX.Core
|
|||
|
||||
public SAV3RSBox(byte[] data, SAV3GCMemoryCard MC) : this(data) { this.MC = MC; BAK = MC.Data; }
|
||||
|
||||
public SAV3RSBox(byte[] data = null)
|
||||
public SAV3RSBox() : base(SaveUtil.SIZE_G3BOX)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G3BOX];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
Box = 0;
|
||||
ClearBoxes();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
if (SaveUtil.GetIsG3BOXSAV(Data) != GameVersion.RSBOX)
|
||||
return;
|
||||
public SAV3RSBox(byte[] data) : base(data)
|
||||
{
|
||||
InitializeData();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
Blocks = new BlockInfoRSBOX[2*BLOCK_COUNT];
|
||||
private void Initialize()
|
||||
{
|
||||
Personal = PersonalTable.RS;
|
||||
HeldItems = Legal.HeldItems_RS;
|
||||
}
|
||||
|
||||
private void InitializeData()
|
||||
{
|
||||
Blocks = new BlockInfoRSBOX[2 * BLOCK_COUNT];
|
||||
for (int i = 0; i < Blocks.Length; i++)
|
||||
{
|
||||
int offset = BLOCK_SIZE + (i * BLOCK_SIZE);
|
||||
|
@ -33,10 +45,10 @@ namespace PKHeX.Core
|
|||
}
|
||||
|
||||
// Detect active save
|
||||
int[] SaveCounts = Blocks.Select(block => (int)block.SaveCount).ToArray();
|
||||
int[] SaveCounts = Blocks.Select(block => (int) block.SaveCount).ToArray();
|
||||
SaveCount = SaveCounts.Max();
|
||||
int ActiveSAV = Array.IndexOf(SaveCounts, SaveCount) / BLOCK_COUNT;
|
||||
Blocks = Blocks.Skip(ActiveSAV*BLOCK_COUNT).Take(BLOCK_COUNT).OrderBy(b => b.ID).ToArray();
|
||||
Blocks = Blocks.Skip(ActiveSAV * BLOCK_COUNT).Take(BLOCK_COUNT).OrderBy(b => b.ID).ToArray();
|
||||
|
||||
// Set up PC data buffer beyond end of save file.
|
||||
Box = Data.Length;
|
||||
|
@ -45,17 +57,11 @@ namespace PKHeX.Core
|
|||
// Copy block to the allocated location
|
||||
const int copySize = BLOCK_SIZE - 0x10;
|
||||
foreach (var b in Blocks)
|
||||
Array.Copy(Data, b.Offset + 0xC, Data, (int)(Box + (b.ID*copySize)), copySize);
|
||||
|
||||
Personal = PersonalTable.RS;
|
||||
HeldItems = Legal.HeldItems_RS;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
Array.Copy(Data, b.Offset + 0xC, Data, (int) (Box + (b.ID * copySize)), copySize);
|
||||
}
|
||||
|
||||
private readonly BlockInfoRSBOX[] Blocks;
|
||||
private readonly int SaveCount;
|
||||
private BlockInfoRSBOX[] Blocks;
|
||||
private int SaveCount;
|
||||
private const int BLOCK_COUNT = 23;
|
||||
private const int BLOCK_SIZE = 0x2000;
|
||||
private const int SIZE_RESERVED = BLOCK_COUNT * BLOCK_SIZE; // unpacked box data
|
||||
|
|
|
@ -18,26 +18,32 @@ namespace PKHeX.Core
|
|||
private const int SLOT_START = 0x6000;
|
||||
private const int SLOT_COUNT = 2;
|
||||
|
||||
private readonly int SaveCount = -1;
|
||||
private readonly int SaveIndex = -1;
|
||||
private readonly int Memo, Shadow;
|
||||
private readonly StrategyMemo StrategyMemo;
|
||||
private readonly ShadowInfoTableXD ShadowInfo;
|
||||
private int SaveCount = -1;
|
||||
private int SaveIndex = -1;
|
||||
private int Memo;
|
||||
private int Shadow;
|
||||
private StrategyMemo StrategyMemo;
|
||||
private ShadowInfoTableXD ShadowInfo;
|
||||
public int MaxShadowID => ShadowInfo.Count;
|
||||
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries, LegalCologne, LegalDisc;
|
||||
private readonly int OFS_PouchCologne, OFS_PouchDisc;
|
||||
private int OFS_PouchCologne;
|
||||
private int OFS_PouchDisc;
|
||||
private readonly int[] subOffsets = new int[16];
|
||||
public SAV3XD(byte[] data, SAV3GCMemoryCard MC) : this(data) { this.MC = MC; BAK = MC.Data; }
|
||||
|
||||
public SAV3XD(byte[] data = null)
|
||||
public SAV3XD() : base(SaveUtil.SIZE_G3XD)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G3XD];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
if (SaveUtil.GetIsG3XDSAV(Data) != GameVersion.XD)
|
||||
return;
|
||||
public SAV3XD(byte[] data) : base(data)
|
||||
{
|
||||
InitializeData();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void InitializeData()
|
||||
{
|
||||
// Scan all 3 save slots for the highest counter
|
||||
for (int i = 0; i < SLOT_COUNT; i++)
|
||||
{
|
||||
|
@ -71,6 +77,7 @@ namespace PKHeX.Core
|
|||
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;
|
||||
|
@ -82,7 +89,10 @@ namespace PKHeX.Core
|
|||
|
||||
StrategyMemo = new StrategyMemo(Data, Memo, xd: true);
|
||||
ShadowInfo = new ShadowInfoTableXD(Data.Skip(Shadow).Take(subLength[7]).ToArray());
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
OFS_PouchHeldItem = Trainer1 + 0x4C8;
|
||||
OFS_PouchKeyItem = Trainer1 + 0x540;
|
||||
OFS_PouchBalls = Trainer1 + 0x5EC;
|
||||
|
@ -90,21 +100,9 @@ namespace PKHeX.Core
|
|||
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_XD;
|
||||
LegalDisc = Legal.Pouch_Disc_XD;
|
||||
|
||||
Personal = PersonalTable.RS;
|
||||
HeldItems = Legal.HeldItems_XD;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
|
||||
// Since PartyCount is not stored in the save file,
|
||||
// Count up how many party slots are active.
|
||||
for (int i = 0; i < 6; i++)
|
||||
|
@ -329,13 +327,13 @@ namespace PKHeX.Core
|
|||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch3GC(InventoryType.Items, LegalItems, 999, OFS_PouchHeldItem, 30), // 20 COLO, 30 XD
|
||||
new InventoryPouch3GC(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem, 43),
|
||||
new InventoryPouch3GC(InventoryType.Balls, LegalBalls, 999, OFS_PouchBalls, 16),
|
||||
new InventoryPouch3GC(InventoryType.TMHMs, LegalTMHMs, 999, OFS_PouchTMHM, 64),
|
||||
new InventoryPouch3GC(InventoryType.Berries, LegalBerries, 999, OFS_PouchBerry, 46),
|
||||
new InventoryPouch3GC(InventoryType.Medicine, LegalCologne, 999, OFS_PouchCologne, 3), // Cologne
|
||||
new InventoryPouch3GC(InventoryType.BattleItems, LegalDisc, 999, OFS_PouchDisc, 60)
|
||||
new InventoryPouch3GC(InventoryType.Items, Legal.Pouch_Items_XD, 999, OFS_PouchHeldItem, 30), // 20 COLO, 30 XD
|
||||
new InventoryPouch3GC(InventoryType.KeyItems, Legal.Pouch_Key_XD, 1, OFS_PouchKeyItem, 43),
|
||||
new InventoryPouch3GC(InventoryType.Balls, Legal.Pouch_Ball_RS, 999, OFS_PouchBalls, 16),
|
||||
new InventoryPouch3GC(InventoryType.TMHMs, Legal.Pouch_TM_RS, 999, OFS_PouchTMHM, 64),
|
||||
new InventoryPouch3GC(InventoryType.Berries, Legal.Pouch_Berries_RS, 999, OFS_PouchBerry, 46),
|
||||
new InventoryPouch3GC(InventoryType.Medicine, Legal.Pouch_Cologne_XD, 999, OFS_PouchCologne, 3), // Cologne
|
||||
new InventoryPouch3GC(InventoryType.BattleItems, Legal.Pouch_Disc_XD, 999, OFS_PouchDisc, 60)
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
|
|
|
@ -13,34 +13,41 @@ namespace PKHeX.Core
|
|||
public override string Filter => (Footer.Length > 0 ? "DeSmuME DSV|*.dsv|" : string.Empty) + "SAV File|*.sav|All Files|*.*";
|
||||
public override string Extension => ".sav";
|
||||
|
||||
public SAV4(byte[] data = null, GameVersion versionOverride = GameVersion.Any)
|
||||
public SAV4(GameVersion versionOverride = GameVersion.HGSS) : base(SaveUtil.SIZE_G4RAW)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G4RAW];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
Version = versionOverride;
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV4(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data)
|
||||
{
|
||||
// Get Version
|
||||
if (data == null)
|
||||
Version = GameVersion.HGSS;
|
||||
else if (versionOverride != GameVersion.Any)
|
||||
Version = versionOverride;
|
||||
else Version = SaveUtil.GetIsG4SAV(Data);
|
||||
Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG4SAV(Data);
|
||||
if (Version == GameVersion.Invalid)
|
||||
return;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
generalBlock = GetActiveGeneralBlock();
|
||||
storageBlock = GetActiveStorageBlock();
|
||||
GetSAVOffsets();
|
||||
|
||||
switch (Version)
|
||||
{
|
||||
case GameVersion.DP: Personal = PersonalTable.DP; break;
|
||||
case GameVersion.Pt: Personal = PersonalTable.Pt; break;
|
||||
case GameVersion.HGSS: Personal = PersonalTable.HGSS; break;
|
||||
case GameVersion.DP:
|
||||
Personal = PersonalTable.DP;
|
||||
break;
|
||||
case GameVersion.Pt:
|
||||
Personal = PersonalTable.Pt;
|
||||
break;
|
||||
case GameVersion.HGSS:
|
||||
Personal = PersonalTable.HGSS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
// Configuration
|
||||
|
@ -133,8 +140,8 @@ namespace PKHeX.Core
|
|||
}
|
||||
|
||||
// Blocks & Offsets
|
||||
private readonly int generalBlock = -1; // Small Block
|
||||
private readonly int storageBlock = -1; // Big Block
|
||||
private int generalBlock = -1; // Small Block
|
||||
private int storageBlock = -1; // Big Block
|
||||
private int SBO => 0x40000 * storageBlock;
|
||||
public int GBO => 0x40000 * generalBlock;
|
||||
|
||||
|
|
|
@ -16,15 +16,26 @@ namespace PKHeX.Core
|
|||
|
||||
private const int SAVE_COUNT = 4;
|
||||
|
||||
public SAV4BR(byte[] data = null)
|
||||
public SAV4BR() : base(SaveUtil.SIZE_G4BR)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G4BR];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
ClearBoxes();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
if (SaveUtil.GetIsG4BRSAV(Data) != GameVersion.BATREV)
|
||||
return;
|
||||
public SAV4BR(byte[] data) : base(data)
|
||||
{
|
||||
InitializeData(data);
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Personal = PersonalTable.DP;
|
||||
HeldItems = Legal.HeldItems_DP;
|
||||
}
|
||||
|
||||
private void InitializeData(byte[] data)
|
||||
{
|
||||
Data = DecryptPBRSaveData(data);
|
||||
|
||||
// Detect active save
|
||||
|
@ -46,12 +57,6 @@ namespace PKHeX.Core
|
|||
}
|
||||
|
||||
CurrentSlot = SaveSlots[0];
|
||||
|
||||
Personal = PersonalTable.DP;
|
||||
HeldItems = Legal.HeldItems_DP;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
private bool IsOTNamePresent(int i)
|
||||
|
@ -59,7 +64,7 @@ namespace PKHeX.Core
|
|||
return BitConverter.ToUInt16(Data, 0x390 + (0x6FF00 * i)) != 0;
|
||||
}
|
||||
|
||||
private readonly uint SaveCount;
|
||||
private uint SaveCount;
|
||||
|
||||
protected override byte[] GetFinalData()
|
||||
{
|
||||
|
|
|
@ -1,111 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Generation 5 <see cref="SaveFile"/> object.
|
||||
/// </summary>
|
||||
public sealed class SAV5 : SaveFile
|
||||
public abstract class SAV5 : SaveFile
|
||||
{
|
||||
// Save Data Attributes
|
||||
protected override PKM GetPKM(byte[] data) => new PK5(data);
|
||||
protected override byte[] DecryptPKM(byte[] data) => PKX.DecryptArray45(data);
|
||||
|
||||
protected override string BAKText => $"{OT} ({(GameVersion)Game}) - {PlayTimeString}";
|
||||
public override string Filter => (Footer.Length != 0 ? "DeSmuME DSV|*.dsv|" : string.Empty) + "SAV File|*.sav|All Files|*.*";
|
||||
public override string Extension => ".sav";
|
||||
|
||||
public SAV5(byte[] data = null, GameVersion versionOverride = GameVersion.Any)
|
||||
{
|
||||
Data = data ?? new byte[SaveUtil.SIZE_G5RAW];
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
|
||||
// Get Version
|
||||
if (data == null)
|
||||
Version = GameVersion.B2W2;
|
||||
else if (versionOverride != GameVersion.Any)
|
||||
Version = versionOverride;
|
||||
else Version = SaveUtil.GetIsG5SAV(Data);
|
||||
if (Version == GameVersion.Invalid)
|
||||
return;
|
||||
|
||||
// First blocks are always the same position/size
|
||||
PCLayout = 0x0;
|
||||
Box = 0x400;
|
||||
Party = 0x18E00;
|
||||
Trainer1 = 0x19400;
|
||||
WondercardData = 0x1C800;
|
||||
AdventureInfo = 0x1D900;
|
||||
|
||||
// Different Offsets for later blocks
|
||||
switch (Version)
|
||||
{
|
||||
case GameVersion.BW:
|
||||
BattleBox = 0x20A00;
|
||||
Trainer2 = 0x21200;
|
||||
EventConst = 0x20100;
|
||||
EventFlag = EventConst + 0x27C;
|
||||
Daycare = 0x20E00;
|
||||
PokeDex = 0x21600;
|
||||
PokeDexLanguageFlags = PokeDex + 0x320;
|
||||
BattleSubway = 0x21D00;
|
||||
CGearInfoOffset = 0x1C000;
|
||||
CGearDataOffset = 0x52000;
|
||||
EntreeForestOffset = 0x22C00;
|
||||
|
||||
// Inventory offsets are the same for each game.
|
||||
OFS_PouchHeldItem = 0x18400; // 0x188D7
|
||||
OFS_PouchKeyItem = 0x188D8; // 0x18A23
|
||||
OFS_PouchTMHM = 0x18A24; // 0x18BD7
|
||||
OFS_PouchMedicine = 0x18BD8; // 0x18C97
|
||||
OFS_PouchBerry = 0x18C98; // 0x18DBF
|
||||
LegalItems = Legal.Pouch_Items_BW;
|
||||
LegalKeyItems = Legal.Pouch_Key_BW;
|
||||
LegalTMHMs = Legal.Pouch_TMHM_BW;
|
||||
LegalMedicine = Legal.Pouch_Medicine_BW;
|
||||
LegalBerries = Legal.Pouch_Berries_BW;
|
||||
|
||||
Personal = PersonalTable.BW;
|
||||
break;
|
||||
case GameVersion.B2W2: // B2W2
|
||||
BattleBox = 0x20900;
|
||||
Trainer2 = 0x21100;
|
||||
EventConst = 0x1FF00;
|
||||
EventFlag = EventConst + 0x35E;
|
||||
Daycare = 0x20D00;
|
||||
PokeDex = 0x21400;
|
||||
PokeDexLanguageFlags = PokeDex + 0x328; // forme flags size is + 8 from bw with new formes (therians)
|
||||
BattleSubway = 0x21B00;
|
||||
CGearInfoOffset = 0x1C000;
|
||||
CGearDataOffset = 0x52800;
|
||||
EntreeForestOffset = 0x22A00;
|
||||
|
||||
// Inventory offsets are the same for each game.
|
||||
OFS_PouchHeldItem = 0x18400; // 0x188D7
|
||||
OFS_PouchKeyItem = 0x188D8; // 0x18A23
|
||||
OFS_PouchTMHM = 0x18A24; // 0x18BD7
|
||||
OFS_PouchMedicine = 0x18BD8; // 0x18C97
|
||||
OFS_PouchBerry = 0x18C98; // 0x18DBF
|
||||
LegalItems = Legal.Pouch_Items_BW;
|
||||
LegalKeyItems = Legal.Pouch_Key_B2W2;
|
||||
LegalTMHMs = Legal.Pouch_TMHM_BW;
|
||||
LegalMedicine = Legal.Pouch_Medicine_BW;
|
||||
LegalBerries = Legal.Pouch_Berries_BW;
|
||||
|
||||
Personal = PersonalTable.B2W2;
|
||||
break;
|
||||
}
|
||||
HeldItems = Legal.HeldItems_BW;
|
||||
Blocks = Version == GameVersion.BW ? BlockInfoNDS.BlocksBW : BlockInfoNDS.BlocksB2W2;
|
||||
|
||||
if (!Exportable)
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
// Configuration
|
||||
public override SaveFile Clone() => new SAV5((byte[])Data.Clone(), Version) {Footer = (byte[])Footer.Clone()};
|
||||
|
||||
public override int SIZE_STORED => PKX.SIZE_5STORED;
|
||||
protected override int SIZE_PARTY => PKX.SIZE_5PARTY;
|
||||
public override PKM BlankPKM => new PK5();
|
||||
|
@ -116,95 +25,79 @@ namespace PKHeX.Core
|
|||
public override int Generation => 5;
|
||||
public override int OTLength => 7;
|
||||
public override int NickLength => 10;
|
||||
protected override int EventConstMax => (Version == GameVersion.BW ? 0x27C : 0x35E) >> 1;
|
||||
protected override int EventFlagMax => (Version == GameVersion.BW ? 0x16C : 0x17F) << 3;
|
||||
protected override int GiftCountMax => 12;
|
||||
|
||||
public override int MaxMoveID => Legal.MaxMoveID_5;
|
||||
public override int MaxSpeciesID => Legal.MaxSpeciesID_5;
|
||||
public override int MaxItemID => Version == GameVersion.BW ? Legal.MaxItemID_5_BW : Legal.MaxItemID_5_B2W2;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_5;
|
||||
public override int MaxBallID => Legal.MaxBallID_5;
|
||||
public override int MaxGameID => Legal.MaxGameID_5; // B2
|
||||
|
||||
protected SAV5(int size) : base(size)
|
||||
{
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
protected SAV5(byte[] data) : base(data)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public override GameVersion Version
|
||||
{
|
||||
get => (GameVersion)Game;
|
||||
protected set => Game = (int)value;
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
// First blocks are always the same position/size
|
||||
PCLayout = 0x0;
|
||||
Box = 0x400;
|
||||
Party = 0x18E00;
|
||||
Trainer1 = 0x19400;
|
||||
WondercardData = 0x1C800;
|
||||
AdventureInfo = 0x1D900;
|
||||
|
||||
HeldItems = Legal.HeldItems_BW;
|
||||
BoxLayout = new BoxLayout5(this, PCLayout);
|
||||
MysteryBlock = new MysteryBlock5(this, WondercardData);
|
||||
PlayerData = new PlayerData5(this, Trainer1);
|
||||
}
|
||||
|
||||
// Blocks & Offsets
|
||||
public readonly IReadOnlyList<BlockInfoNDS> Blocks;
|
||||
protected IReadOnlyList<BlockInfoNDS> Blocks;
|
||||
protected override void SetChecksums() => Blocks.SetChecksums(Data);
|
||||
public override bool ChecksumsValid => Blocks.GetChecksumsValid(Data);
|
||||
public override string ChecksumInfo => Blocks.GetChecksumInfo(Data);
|
||||
|
||||
private const int wcSeed = 0x1D290;
|
||||
protected MyItem Items { get; set; }
|
||||
public Zukan Zukan { get; protected set; }
|
||||
public Misc5 MiscBlock { get; protected set; }
|
||||
private MysteryBlock5 MysteryBlock { get; set; }
|
||||
protected Daycare5 DaycareBlock { get; set; }
|
||||
public BoxLayout5 BoxLayout { get; private set; }
|
||||
public PlayerData5 PlayerData { get; private set; }
|
||||
public BattleSubway5 BattleSubwayBlock { get; protected set; }
|
||||
|
||||
public readonly int CGearInfoOffset, CGearDataOffset;
|
||||
private readonly int EntreeForestOffset;
|
||||
private readonly int Trainer2, AdventureInfo, BattleSubway;
|
||||
public readonly int PokeDexLanguageFlags;
|
||||
protected int CGearInfoOffset;
|
||||
protected int CGearDataOffset;
|
||||
protected int EntreeForestOffset;
|
||||
protected int Trainer2;
|
||||
private int AdventureInfo;
|
||||
protected int BattleSubway;
|
||||
public int PokeDexLanguageFlags;
|
||||
|
||||
// Daycare
|
||||
public override int DaycareSeedSize => 16;
|
||||
|
||||
public override int GetDaycareSlotOffset(int loc, int slot)
|
||||
{
|
||||
return Daycare + 4 + (0xE4 * slot);
|
||||
}
|
||||
|
||||
public override string GetDaycareRNGSeed(int loc)
|
||||
{
|
||||
if (Version != GameVersion.B2W2)
|
||||
return null;
|
||||
var data = Data.Skip(Daycare + 0x1CC).Take(DaycareSeedSize/2).Reverse().ToArray();
|
||||
return BitConverter.ToString(data).Replace("-", string.Empty);
|
||||
}
|
||||
|
||||
public override uint? GetDaycareEXP(int loc, int slot)
|
||||
{
|
||||
return BitConverter.ToUInt32(Data, Daycare + 4 + 0xDC + (slot * 0xE4));
|
||||
}
|
||||
|
||||
public override bool? IsDaycareOccupied(int loc, int slot)
|
||||
{
|
||||
return BitConverter.ToUInt32(Data, Daycare + (0xE4 * slot)) == 1;
|
||||
}
|
||||
|
||||
public override void SetDaycareEXP(int loc, int slot, uint EXP)
|
||||
{
|
||||
BitConverter.GetBytes(EXP).CopyTo(Data, Daycare + 4 + 0xDC + (slot * 0xE4));
|
||||
}
|
||||
|
||||
public override void SetDaycareOccupied(int loc, int slot, bool occupied)
|
||||
{
|
||||
BitConverter.GetBytes((uint)(occupied ? 1 : 0)).CopyTo(Data, Daycare + 0x1CC);
|
||||
}
|
||||
|
||||
public override void SetDaycareRNGSeed(int loc, string seed)
|
||||
{
|
||||
if (Version != GameVersion.B2W2)
|
||||
return;
|
||||
Enumerable.Range(0, seed.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(seed.Substring(x, 2), 16))
|
||||
.Reverse().ToArray().CopyTo(Data, Daycare + 0x1CC);
|
||||
}
|
||||
|
||||
// Inventory
|
||||
private readonly ushort[] LegalItems, LegalKeyItems, LegalTMHMs, LegalMedicine, LegalBerries;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch4(InventoryType.Items, LegalItems, 999, OFS_PouchHeldItem),
|
||||
new InventoryPouch4(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem),
|
||||
new InventoryPouch4(InventoryType.TMHMs, LegalTMHMs, 1, OFS_PouchTMHM),
|
||||
new InventoryPouch4(InventoryType.Medicine, LegalMedicine, 999, OFS_PouchMedicine),
|
||||
new InventoryPouch4(InventoryType.Berries, LegalBerries, 999, OFS_PouchBerry),
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
public override int DaycareSeedSize => Daycare5.DaycareSeedSize;
|
||||
public override bool? IsDaycareOccupied(int loc, int slot) => DaycareBlock.IsOccupied(slot);
|
||||
public override int GetDaycareSlotOffset(int loc, int slot) => DaycareBlock.GetOffset(slot);
|
||||
public override uint? GetDaycareEXP(int loc, int slot) => DaycareBlock.GetEXP(slot);
|
||||
public override string GetDaycareRNGSeed(int loc) => DaycareBlock.GetSeed()?.ToString("X16");
|
||||
public override void SetDaycareEXP(int loc, int slot, uint EXP) => DaycareBlock.SetEXP(slot, EXP);
|
||||
public override void SetDaycareOccupied(int loc, int slot, bool occupied) => DaycareBlock.SetOccupied(slot, occupied);
|
||||
public override void SetDaycareRNGSeed(int loc, string seed) => DaycareBlock.SetSeed(seed);
|
||||
|
||||
// Storage
|
||||
public override int PartyCount
|
||||
|
@ -213,59 +106,20 @@ namespace PKHeX.Core
|
|||
protected set => Data[Party + 4] = (byte)value;
|
||||
}
|
||||
|
||||
public override int GetBoxOffset(int box)
|
||||
{
|
||||
return Box + (SIZE_STORED * box * 30) + (box * 0x10);
|
||||
}
|
||||
public override int GetBoxOffset(int box) => Box + (SIZE_STORED * box * 30) + (box * 0x10);
|
||||
public override int GetPartyOffset(int slot) => Party + 8 + (SIZE_PARTY * slot);
|
||||
|
||||
public override int GetPartyOffset(int slot)
|
||||
{
|
||||
return Party + 8 + (SIZE_PARTY * slot);
|
||||
}
|
||||
|
||||
public override string GetBoxName(int box)
|
||||
{
|
||||
if (box >= BoxCount)
|
||||
return string.Empty;
|
||||
return Util.TrimFromFFFF(Encoding.Unicode.GetString(Data, GetBoxNameOffset(box), 0x28));
|
||||
}
|
||||
|
||||
public override void SetBoxName(int box, string value)
|
||||
{
|
||||
if (value.Length > 38)
|
||||
return;
|
||||
value += '\uFFFF';
|
||||
var data = Encoding.Unicode.GetBytes(value.PadRight(0x14, '\0'));
|
||||
SetData(data, GetBoxNameOffset(box));
|
||||
}
|
||||
|
||||
private int GetBoxNameOffset(int box) => PCLayout + (0x28 * box) + 4;
|
||||
|
||||
protected override int GetBoxWallpaperOffset(int box)
|
||||
{
|
||||
return PCLayout + 0x3C4 + box;
|
||||
}
|
||||
|
||||
public override int CurrentBox
|
||||
{
|
||||
get => Data[PCLayout];
|
||||
set => Data[PCLayout] = (byte)value;
|
||||
}
|
||||
protected override int GetBoxWallpaperOffset(int box) => BoxLayout.GetBoxWallpaperOffset(box);
|
||||
public override int GetBoxWallpaper(int box) => BoxLayout.GetBoxWallpaper(box);
|
||||
public override void SetBoxWallpaper(int box, int value) => BoxLayout.SetBoxWallpaper(box, value);
|
||||
public override string GetBoxName(int box) => BoxLayout[box];
|
||||
public override void SetBoxName(int box, string value) => BoxLayout[box] = value;
|
||||
public override int CurrentBox { get => BoxLayout.CurrentBox; set => BoxLayout.CurrentBox = value; }
|
||||
|
||||
public override bool BattleBoxLocked
|
||||
{
|
||||
get => BattleBox >= 0 && Data[BattleBox + 0x358] != 0; // wifi/live
|
||||
set { }
|
||||
}
|
||||
|
||||
protected override PKM GetPKM(byte[] data)
|
||||
{
|
||||
return new PK5(data);
|
||||
}
|
||||
|
||||
protected override byte[] DecryptPKM(byte[] data)
|
||||
{
|
||||
return PKX.DecryptArray45(data);
|
||||
get => Data[BattleBox + 0x358] != 0; // wifi/live
|
||||
set => Data[BattleBox + 0x358] = (byte)(value ? 1 : 0);
|
||||
}
|
||||
|
||||
protected override void SetPKM(PKM pkm)
|
||||
|
@ -277,268 +131,26 @@ namespace PKHeX.Core
|
|||
pkm.RefreshChecksum();
|
||||
}
|
||||
|
||||
// Mystery Gift
|
||||
public override MysteryGiftAlbum GiftAlbum
|
||||
{
|
||||
get
|
||||
{
|
||||
uint seed = BitConverter.ToUInt32(Data, wcSeed);
|
||||
MysteryGiftAlbum Info = new MysteryGiftAlbum { Seed = seed };
|
||||
byte[] wcData = GetData(WondercardData, 0xA90); // Encrypted, Decrypt
|
||||
PKX.CryptArray(wcData, seed);
|
||||
|
||||
Info.Flags = new bool[GiftFlagMax];
|
||||
Info.Gifts = new MysteryGift[GiftCountMax];
|
||||
// 0x100 Bytes for Used Flags
|
||||
for (int i = 0; i < GiftFlagMax; i++)
|
||||
Info.Flags[i] = (wcData[i/8] >> i%8 & 0x1) == 1;
|
||||
// 12 PGFs
|
||||
for (int i = 0; i < Info.Gifts.Length; i++)
|
||||
Info.Gifts[i] = new PGF(wcData.Skip(0x100 + (i *PGF.Size)).Take(PGF.Size).ToArray());
|
||||
|
||||
return Info;
|
||||
}
|
||||
set
|
||||
{
|
||||
byte[] wcData = new byte[0xA90];
|
||||
|
||||
// Toss back into byte[]
|
||||
for (int i = 0; i < value.Flags.Length; i++)
|
||||
{
|
||||
if (value.Flags[i])
|
||||
wcData[i/8] |= (byte)(1 << (i & 7));
|
||||
}
|
||||
|
||||
for (int i = 0; i < value.Gifts.Length; i++)
|
||||
value.Gifts[i].Data.CopyTo(wcData, 0x100 + (i *PGF.Size));
|
||||
|
||||
// Decrypted, Encrypt
|
||||
PKX.CryptArray(wcData, value.Seed);
|
||||
|
||||
// Write Back
|
||||
wcData.CopyTo(Data, WondercardData);
|
||||
BitConverter.GetBytes(value.Seed).CopyTo(Data, wcSeed);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool[] MysteryGiftReceivedFlags { get => Array.Empty<bool>(); set { } }
|
||||
protected override MysteryGift[] MysteryGiftCards { get => Array.Empty<MysteryGift>(); set { } }
|
||||
|
||||
// Trainer Info
|
||||
public override string OT
|
||||
{
|
||||
get => GetString(Trainer1 + 0x4, 16);
|
||||
set => SetString(value, OTLength).CopyTo(Data, Trainer1 + 0x4);
|
||||
}
|
||||
|
||||
public override int TID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Trainer1 + 0x14 + 0);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x14 + 0);
|
||||
}
|
||||
|
||||
public override int SID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Trainer1 + 0x14 + 2);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x14 + 2);
|
||||
}
|
||||
|
||||
public override uint Money
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Trainer2);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Trainer2);
|
||||
}
|
||||
|
||||
public override int Gender
|
||||
{
|
||||
get => Data[Trainer1 + 0x21];
|
||||
set => Data[Trainer1 + 0x21] = (byte)value;
|
||||
}
|
||||
|
||||
public override int Language
|
||||
{
|
||||
get => Data[Trainer1 + 0x1E];
|
||||
set => Data[Trainer1 + 0x1E] = (byte)value;
|
||||
}
|
||||
|
||||
public override int Game
|
||||
{
|
||||
get => Data[Trainer1 + 0x1F];
|
||||
set => Data[Trainer1 + 0x1F] = (byte)value;
|
||||
}
|
||||
|
||||
public int Badges
|
||||
{
|
||||
get => Data[Trainer2 + 0x4];
|
||||
set => Data[Trainer2 + 0x4] = (byte)value;
|
||||
}
|
||||
|
||||
public int M
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Trainer1 + 0x180);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x180);
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Trainer1 + 0x186);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x186);
|
||||
}
|
||||
|
||||
public int Z
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Trainer1 + 0x18A);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x18A);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Trainer1 + 0x18E);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x18E);
|
||||
}
|
||||
|
||||
public override int PlayedHours
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Trainer1 + 0x24);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x24);
|
||||
}
|
||||
|
||||
public override int PlayedMinutes
|
||||
{
|
||||
get => Data[Trainer1 + 0x24 + 2];
|
||||
set => Data[Trainer1 + 0x24 + 2] = (byte)value;
|
||||
}
|
||||
|
||||
public override int PlayedSeconds
|
||||
{
|
||||
get => Data[Trainer1 + 0x24 + 3];
|
||||
set => Data[Trainer1 + 0x24 + 3] = (byte)value;
|
||||
}
|
||||
|
||||
// Player Data
|
||||
public override string OT { get => PlayerData.OT; set => PlayerData.OT = value; }
|
||||
public override int TID { get => PlayerData.TID; set => PlayerData.TID = value; }
|
||||
public override int SID { get => PlayerData.SID; set => PlayerData.SID = value; }
|
||||
public override int Language { get => PlayerData.Language; set => PlayerData.Language = value; }
|
||||
public override int Game { get => PlayerData.Game; set => PlayerData.Game = value; }
|
||||
public override int Gender { get => PlayerData.Gender; set => PlayerData.Gender = value; }
|
||||
public override int PlayedHours { get => PlayerData.PlayedHours; set => PlayerData.PlayedHours = value; }
|
||||
public override int PlayedMinutes { get => PlayerData.PlayedMinutes; set => PlayerData.PlayedMinutes = value; }
|
||||
public override int PlayedSeconds { get => PlayerData.PlayedSeconds; set => PlayerData.PlayedSeconds = value; }
|
||||
public override uint Money { get => MiscBlock.Money; set => MiscBlock.Money = value; }
|
||||
public override uint SecondsToStart { get => BitConverter.ToUInt32(Data, AdventureInfo + 0x34); set => BitConverter.GetBytes(value).CopyTo(Data, AdventureInfo + 0x34); }
|
||||
public override uint SecondsToFame { get => BitConverter.ToUInt32(Data, AdventureInfo + 0x3C); set => BitConverter.GetBytes(value).CopyTo(Data, AdventureInfo + 0x3C); }
|
||||
|
||||
public override MysteryGiftAlbum GiftAlbum { get => MysteryBlock.GiftAlbum; set => MysteryBlock.GiftAlbum = value; }
|
||||
public override InventoryPouch[] Inventory { get => Items.Inventory; set => Items.Inventory = value; }
|
||||
|
||||
public int BP
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, BattleSubway);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, BattleSubway);
|
||||
}
|
||||
|
||||
public ushort GetPWTRecord(int id) => GetPWTRecord((PWTRecordID) id);
|
||||
|
||||
public ushort GetPWTRecord(PWTRecordID id)
|
||||
{
|
||||
if (id < PWTRecordID.Normal || id > PWTRecordID.MixMaster)
|
||||
throw new ArgumentException(nameof(id));
|
||||
int ofs = 0x2375C + ((int)id * 2);
|
||||
return BitConverter.ToUInt16(Data, ofs);
|
||||
}
|
||||
|
||||
public void SetPWTRecord(int id, ushort value) => SetPWTRecord((PWTRecordID) id, value);
|
||||
|
||||
public void SetPWTRecord(PWTRecordID id, ushort value)
|
||||
{
|
||||
if (id < PWTRecordID.Normal || id > PWTRecordID.MixMaster)
|
||||
throw new ArgumentException(nameof(id));
|
||||
int ofs = 0x2375C + ((int)id * 2);
|
||||
SetData(BitConverter.GetBytes(value), ofs);
|
||||
}
|
||||
|
||||
protected override void SetDex(PKM pkm)
|
||||
{
|
||||
if (pkm.Species == 0)
|
||||
return;
|
||||
if (pkm.Species > MaxSpeciesID)
|
||||
return;
|
||||
if (Version == GameVersion.Invalid)
|
||||
return;
|
||||
if (PokeDex < 0)
|
||||
return;
|
||||
|
||||
const int brSize = 0x54;
|
||||
int bit = pkm.Species - 1;
|
||||
int gender = pkm.Gender % 2; // genderless -> male
|
||||
int shiny = pkm.IsShiny ? 1 : 0;
|
||||
int shift = (shiny * 2) + gender + 1;
|
||||
int shiftoff = (shiny * brSize * 2) + (gender * brSize) + brSize;
|
||||
int ofs = PokeDex + 0x8 + (bit >> 3);
|
||||
|
||||
// Set the Species Owned Flag
|
||||
Data[ofs + (brSize * 0)] |= (byte)(1 << (bit % 8));
|
||||
|
||||
// Set the [Species/Gender/Shiny] Seen Flag
|
||||
Data[PokeDex + 0x8 + shiftoff + (bit / 8)] |= (byte)(1 << (bit&7));
|
||||
|
||||
// Set the Display flag if none are set
|
||||
bool Displayed = false;
|
||||
Displayed |= (Data[ofs + (brSize * 5)] & (byte)(1 << (bit&7))) != 0;
|
||||
Displayed |= (Data[ofs + (brSize * 6)] & (byte)(1 << (bit&7))) != 0;
|
||||
Displayed |= (Data[ofs + (brSize * 7)] & (byte)(1 << (bit&7))) != 0;
|
||||
Displayed |= (Data[ofs + (brSize * 8)] & (byte)(1 << (bit&7))) != 0;
|
||||
if (!Displayed) // offset is already biased by brSize, reuse shiftoff but for the display flags.
|
||||
Data[ofs + (brSize *(shift + 4))] |= (byte)(1 << (bit&7));
|
||||
|
||||
// Set the Language
|
||||
if (bit < 493) // shifted by 1, Gen5 species do not have international language bits
|
||||
{
|
||||
int lang = pkm.Language - 1; if (lang > 5) lang--; // 0-6 language vals
|
||||
if (lang < 0) lang = 1;
|
||||
Data[PokeDexLanguageFlags + (((bit * 7) + lang)>>3)] |= (byte)(1 << (((bit * 7) + lang) & 7));
|
||||
}
|
||||
|
||||
// Formes
|
||||
int fc = Personal[pkm.Species].FormeCount;
|
||||
int f = B2W2 ? DexFormUtil.GetDexFormIndexB2W2(pkm.Species, fc) : DexFormUtil.GetDexFormIndexBW(pkm.Species, fc);
|
||||
if (f < 0) return;
|
||||
|
||||
int FormLen = B2W2 ? 0xB : 0x9;
|
||||
int FormDex = PokeDex + 0x8 + (brSize * 9);
|
||||
bit = f + pkm.AltForm;
|
||||
|
||||
// Set Form Seen Flag
|
||||
Data[FormDex + (FormLen * shiny) + (bit>>3)] |= (byte)(1 << (bit&7));
|
||||
|
||||
// Set Displayed Flag if necessary, check all flags
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
bit = f + i;
|
||||
if ((Data[FormDex + (FormLen * 2) + (bit>>3)] & (byte)(1 << (bit&7))) != 0) // Nonshiny
|
||||
return; // already set
|
||||
if ((Data[FormDex + (FormLen * 3) + (bit>>3)] & (byte)(1 << (bit&7))) != 0) // Shiny
|
||||
return; // already set
|
||||
}
|
||||
bit = f + pkm.AltForm;
|
||||
Data[FormDex + (FormLen * (2 + shiny)) + (bit>>3)] |= (byte)(1 << (bit&7));
|
||||
}
|
||||
|
||||
public override bool GetCaught(int species)
|
||||
{
|
||||
int bit = species - 1;
|
||||
int bd = bit >> 3; // div8
|
||||
int bm = bit & 7; // mod8
|
||||
int ofs = PokeDex // Raw Offset
|
||||
+ 0x08; // Magic + Flags
|
||||
return (1 << bm & Data[ofs + bd]) != 0;
|
||||
}
|
||||
|
||||
public override bool GetSeen(int species)
|
||||
{
|
||||
const int brSize = 0x54;
|
||||
|
||||
int bit = species - 1;
|
||||
int bd = bit >> 3; // div8
|
||||
int bm = bit & 7; // mod8
|
||||
int ofs = PokeDex // Raw Offset
|
||||
+ 0x08; // Magic + Flags
|
||||
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
if ((1 << bm & Data[ofs + bd + (i * brSize)]) != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm);
|
||||
public override bool GetCaught(int species) => Zukan.GetCaught(species);
|
||||
public override bool GetSeen(int species) => Zukan.GetSeen(species);
|
||||
|
||||
public override string GetString(byte[] data, int offset, int length) => StringConverter.GetString5(data, offset, length);
|
||||
|
||||
|
@ -562,7 +174,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
get
|
||||
{
|
||||
byte[] data = new byte[0x2600];
|
||||
byte[] data = new byte[CGearBackground.SIZE_CGB];
|
||||
if (CGearSkinPresent)
|
||||
Array.Copy(Data, CGearDataOffset, data, 0, data.Length);
|
||||
return data;
|
||||
|
|
40
PKHeX.Core/Saves/SAV5B2W2.cs
Normal file
40
PKHeX.Core/Saves/SAV5B2W2.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public class SAV5B2W2 : SAV5
|
||||
{
|
||||
public SAV5B2W2() : base(SaveUtil.SIZE_G5RAW) => Initialize();
|
||||
public SAV5B2W2(byte[] data) : base(data) => Initialize();
|
||||
public override SaveFile Clone() => new SAV5B2W2((byte[])Data.Clone()) { Footer = (byte[])Footer.Clone() };
|
||||
protected override int EventConstMax => 0x1AF; // this doesn't seem right?
|
||||
protected override int EventFlagMax => 0xBF8;
|
||||
public override int MaxItemID => Legal.MaxItemID_5_B2W2;
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Blocks = BlockInfoNDS.BlocksB2W2;
|
||||
Personal = PersonalTable.B2W2;
|
||||
|
||||
Items = new MyItem5B2W2(this, 0x18400);
|
||||
BattleBox = 0x20900;
|
||||
Trainer2 = 0x21100;
|
||||
EventConst = 0x1FF00;
|
||||
EventFlag = EventConst + 0x35E;
|
||||
Daycare = 0x20D00;
|
||||
PokeDex = 0x21400;
|
||||
PokeDexLanguageFlags = PokeDex + 0x328; // forme flags size is + 8 from bw with new formes (therians)
|
||||
BattleSubway = 0x21B00;
|
||||
CGearInfoOffset = 0x1C000;
|
||||
CGearDataOffset = 0x52800;
|
||||
EntreeForestOffset = 0x22A00;
|
||||
Zukan = new Zukan5(this, PokeDex, PokeDexLanguageFlags);
|
||||
DaycareBlock = new Daycare5(this, Daycare);
|
||||
|
||||
MiscBlock = new Misc5(this, Trainer2);
|
||||
PWTBlock = new PWTBlock5(this, 0x23700);
|
||||
DaycareBlock = new Daycare5(this, Daycare);
|
||||
BattleSubwayBlock = new BattleSubway5(this, BattleSubway);
|
||||
}
|
||||
|
||||
public PWTBlock5 PWTBlock { get; private set; }
|
||||
}
|
||||
}
|
37
PKHeX.Core/Saves/SAV5BW.cs
Normal file
37
PKHeX.Core/Saves/SAV5BW.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public class SAV5BW : SAV5
|
||||
{
|
||||
public SAV5BW() : base(SaveUtil.SIZE_G5RAW) => Initialize();
|
||||
public SAV5BW(byte[] data) : base(data) => Initialize();
|
||||
public override SaveFile Clone() => new SAV5BW((byte[])Data.Clone()) { Footer = (byte[])Footer.Clone() };
|
||||
protected override int EventConstMax => 0x13E;
|
||||
protected override int EventFlagMax => 0xB60;
|
||||
public override int MaxItemID => Legal.MaxItemID_5_BW;
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Blocks = BlockInfoNDS.BlocksBW;
|
||||
Personal = PersonalTable.BW;
|
||||
|
||||
Items = new MyItem5BW(this, 0x18400);
|
||||
|
||||
BattleBox = 0x20A00;
|
||||
Trainer2 = 0x21200;
|
||||
EventConst = 0x20100;
|
||||
EventFlag = EventConst + 0x27C;
|
||||
Daycare = 0x20E00;
|
||||
PokeDex = 0x21600;
|
||||
PokeDexLanguageFlags = PokeDex + 0x320;
|
||||
BattleSubway = 0x21D00;
|
||||
CGearInfoOffset = 0x1C000;
|
||||
CGearDataOffset = 0x52000;
|
||||
EntreeForestOffset = 0x22C00;
|
||||
MiscBlock = new Misc5(this, Trainer2);
|
||||
Zukan = new Zukan5(this, PokeDex, PokeDexLanguageFlags);
|
||||
DaycareBlock = new Daycare5(this, Daycare);
|
||||
BattleSubwayBlock = new BattleSubway5(this, BattleSubway);
|
||||
// Inventory offsets are the same for each game.
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
351
PKHeX.Core/Saves/SAV6AO.cs
Normal file
351
PKHeX.Core/Saves/SAV6AO.cs
Normal file
|
@ -0,0 +1,351 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Generation 6 <see cref="SaveFile"/> object for <see cref="GameVersion.ORAS"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="SAV6" />
|
||||
public sealed class SAV6AO : SAV6, IPokePuff, IOPower, ILink
|
||||
{
|
||||
public SAV6AO(byte[] data) : base(data, BlocksAO, boAO) => Initialize();
|
||||
public SAV6AO() : base(SaveUtil.SIZE_G6ORAS, BlocksAO, boAO) => Initialize();
|
||||
public override SaveFile Clone() => new SAV6AO((byte[])Data.Clone());
|
||||
public override int MaxMoveID => Legal.MaxMoveID_6_AO;
|
||||
public override int MaxItemID => Legal.MaxItemID_6_AO;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_6_AO;
|
||||
|
||||
private const int boAO = SaveUtil.SIZE_G6ORAS - 0x200;
|
||||
|
||||
public static readonly BlockInfo[] BlocksAO =
|
||||
{
|
||||
new BlockInfo6 (boAO, 00, 0x00000, 0x002C8),
|
||||
new BlockInfo6 (boAO, 01, 0x00400, 0x00B90),
|
||||
new BlockInfo6 (boAO, 02, 0x01000, 0x0002C),
|
||||
new BlockInfo6 (boAO, 03, 0x01200, 0x00038),
|
||||
new BlockInfo6 (boAO, 04, 0x01400, 0x00150),
|
||||
new BlockInfo6 (boAO, 05, 0x01600, 0x00004),
|
||||
new BlockInfo6 (boAO, 06, 0x01800, 0x00008),
|
||||
new BlockInfo6 (boAO, 07, 0x01A00, 0x001C0),
|
||||
new BlockInfo6 (boAO, 08, 0x01C00, 0x000BE),
|
||||
new BlockInfo6 (boAO, 09, 0x01E00, 0x00024),
|
||||
new BlockInfo6 (boAO, 10, 0x02000, 0x02100),
|
||||
new BlockInfo6 (boAO, 11, 0x04200, 0x00130),
|
||||
new BlockInfo6 (boAO, 12, 0x04400, 0x00440),
|
||||
new BlockInfo6 (boAO, 13, 0x04A00, 0x00574),
|
||||
new BlockInfo6 (boAO, 14, 0x05000, 0x04E28),
|
||||
new BlockInfo6 (boAO, 15, 0x0A000, 0x04E28),
|
||||
new BlockInfo6 (boAO, 16, 0x0F000, 0x04E28),
|
||||
new BlockInfo6 (boAO, 17, 0x14000, 0x00170),
|
||||
new BlockInfo6 (boAO, 18, 0x14200, 0x0061C),
|
||||
new BlockInfo6 (boAO, 19, 0x14A00, 0x00504),
|
||||
new BlockInfo6 (boAO, 20, 0x15000, 0x011CC),
|
||||
new BlockInfo6 (boAO, 21, 0x16200, 0x00644),
|
||||
new BlockInfo6 (boAO, 22, 0x16A00, 0x00104),
|
||||
new BlockInfo6 (boAO, 23, 0x16C00, 0x00004),
|
||||
new BlockInfo6 (boAO, 24, 0x16E00, 0x00420),
|
||||
new BlockInfo6 (boAO, 25, 0x17400, 0x00064),
|
||||
new BlockInfo6 (boAO, 26, 0x17600, 0x003F0),
|
||||
new BlockInfo6 (boAO, 27, 0x17A00, 0x0070C),
|
||||
new BlockInfo6 (boAO, 28, 0x18200, 0x00180),
|
||||
new BlockInfo6 (boAO, 29, 0x18400, 0x00004),
|
||||
new BlockInfo6 (boAO, 30, 0x18600, 0x0000C),
|
||||
new BlockInfo6 (boAO, 31, 0x18800, 0x00048),
|
||||
new BlockInfo6 (boAO, 32, 0x18A00, 0x00054),
|
||||
new BlockInfo6 (boAO, 33, 0x18C00, 0x00644),
|
||||
new BlockInfo6 (boAO, 34, 0x19400, 0x005C8),
|
||||
new BlockInfo6 (boAO, 35, 0x19A00, 0x002F8),
|
||||
new BlockInfo6 (boAO, 36, 0x19E00, 0x01B40),
|
||||
new BlockInfo6 (boAO, 37, 0x1BA00, 0x001F4),
|
||||
new BlockInfo6 (boAO, 38, 0x1BC00, 0x003E0),
|
||||
new BlockInfo6 (boAO, 39, 0x1C000, 0x00216),
|
||||
new BlockInfo6 (boAO, 40, 0x1C400, 0x00640),
|
||||
new BlockInfo6 (boAO, 41, 0x1CC00, 0x01A90),
|
||||
new BlockInfo6 (boAO, 42, 0x1E800, 0x00400),
|
||||
new BlockInfo6 (boAO, 43, 0x1EC00, 0x00618),
|
||||
new BlockInfo6 (boAO, 44, 0x1F400, 0x0025C),
|
||||
new BlockInfo6 (boAO, 45, 0x1F800, 0x00834),
|
||||
new BlockInfo6 (boAO, 46, 0x20200, 0x00318),
|
||||
new BlockInfo6 (boAO, 47, 0x20600, 0x007D0),
|
||||
new BlockInfo6 (boAO, 48, 0x20E00, 0x00C48),
|
||||
new BlockInfo6 (boAO, 49, 0x21C00, 0x00078),
|
||||
new BlockInfo6 (boAO, 50, 0x21E00, 0x00200),
|
||||
new BlockInfo6 (boAO, 51, 0x22000, 0x00C84),
|
||||
new BlockInfo6 (boAO, 52, 0x22E00, 0x00628),
|
||||
new BlockInfo6 (boAO, 53, 0x23600, 0x00400),
|
||||
new BlockInfo6 (boAO, 54, 0x23A00, 0x07AD0),
|
||||
new BlockInfo6 (boAO, 55, 0x2B600, 0x078B0),
|
||||
new BlockInfo6 (boAO, 56, 0x33000, 0x34AD0),
|
||||
new BlockInfo6 (boAO, 57, 0x67C00, 0x0E058),
|
||||
};
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
/* 00: 00000-002C8, 002C8 */ // Puff = 0x00000;
|
||||
/* 01: 00400-00F90, 00B90 */ // MyItem = 0x00400; // Bag
|
||||
/* 02: 01000-0102C, 0002C */ // ItemInfo = 0x1000; // Select Bound Items
|
||||
/* 03: 01200-01238, 00038 */ // GameTime = 0x01200;
|
||||
/* 04: 01400-01550, 00150 */ Trainer1 = 0x01400; // Situation
|
||||
/* 05: 01600-01604, 00004 */ // RandomGroup (rand seeds)
|
||||
/* 06: 01800-01808, 00008 */ PlayTime = 0x1800; // PlayTime
|
||||
/* 07: 01A00-01BC0, 001C0 */ Accessories = 0x1A00; // Fashion
|
||||
/* 08: 01C00-01CBE, 000BE */ // amie minigame records
|
||||
/* 09: 01E00-01E24, 00024 */ // temp variables (u32 id + 32 u8)
|
||||
/* 10: 02000-04100, 02100 */ // FieldMoveModelSave
|
||||
/* 11: 04200-04330, 00130 */ Trainer2 = 0x04200; // Misc
|
||||
/* 12: 04400-04840, 00440 */ PCLayout = 0x04400; // BOX
|
||||
/* 13: 04A00-04F74, 00574 */ BattleBox = 0x04A00; // BattleBox
|
||||
/* 14: 05000-09E28, 04E28 */ PSS = 0x05000;
|
||||
/* 15: 0A000-0EE28, 04E28 */ // PSS2
|
||||
/* 16: 0F000-13E28, 04E28 */ // PSS3
|
||||
/* 17: 14000-14170, 00170 */ // MyStatus
|
||||
/* 18: 14200-1481C, 0061C */ Party = 0x14200; // PokePartySave
|
||||
/* 19: 14A00-14F04, 00504 */ EventConst = 0x14A00; // EventWork
|
||||
/* 20: 15000-161CC, 011CC */ PokeDex = 0x15000; // ZukanData
|
||||
/* 21: 16200-16844, 00644 */ // hologram clips
|
||||
/* 22: 16A00-16B04, 00104 */ Fused = 0x16A00; // UnionPokemon
|
||||
/* 23: 16C00-16C04, 00004 */ // ConfigSave
|
||||
/* 24: 16E00-17220, 00420 */ // Amie decoration stuff
|
||||
/* 25: 17400-17464, 00064 */ // OPower = 0x17400;
|
||||
/* 26: 17600-179F0, 003F0 */ // Strength Rock position (xyz float: 84 entries, 12bytes/entry)
|
||||
/* 27: 17A00-1810C, 0070C */ // Trainer PR Video
|
||||
/* 28: 18200-18380, 00180 */ GTS = 0x18200; // GtsData
|
||||
/* 29: 18400-18404, 00004 */ // Packed Menu Bits
|
||||
/* 30: 18600-1860C, 0000C */ // PSS Profile Q&A (6*questions, 6*answer)
|
||||
/* 31: 18800-18848, 00048 */ // Repel Info, (Swarm?) and other overworld info (roamer)
|
||||
/* 32: 18A00-18A54, 00054 */ // BOSS data fetch history (serial/mystery gift), 4byte intro & 20*4byte entries
|
||||
/* 33: 18C00-19244, 00644 */ // Streetpass history
|
||||
/* 34: 19400-199C8, 005C8 */ // LiveMatchData/BattleSpotData
|
||||
/* 35: 19A00-19CF8, 002F8 */ // MAC Address & Network Connection Logging (0x98 per entry, 5 entries)
|
||||
/* 36: 19E00-1B940, 01B40 */ HoF = 0x19E00; // Dendou
|
||||
/* 37: 1BA00-1BBF4, 001F4 */ MaisonStats = 0x1BBC0; // BattleInstSave
|
||||
/* 38: 1BC00-1BFE0, 003E0 */ Daycare = 0x1BC00; // Sodateya
|
||||
/* 39: 1C000-1C216, 00216 */ // BattleInstSave
|
||||
/* 40: 1C400-1CA40, 00640 */ BerryField = 0x1C400;
|
||||
/* 41: 1CC00-1E690, 01A90 */ WondercardFlags = 0x1CC00; // MysteryGiftSave
|
||||
/* 42: 1E800-1EC00, 00400 */ // Storyline Records
|
||||
/* 43: 1EC00-1F218, 00618 */ SUBE = 0x1D890; // PokeDiarySave
|
||||
/* 44: 1F400-1F65C, 0025C */ // Record = 0x1F400;
|
||||
/* 45: 1F800-20034, 00834 */ // Friend Safari (0x15 per entry, 100 entries)
|
||||
/* 46: 20200-20518, 00318 */ SuperTrain = 0x20200;
|
||||
/* 47: 20600-20DD0, 007D0 */ // Unused (lmao)
|
||||
/* 48: 20E00-21A48, 00C48 */ LinkInfo = 0x20E00;
|
||||
/* 49: 21C00-21C78, 00078 */ // PSS usage info
|
||||
/* 50: 21E00-22000, 00200 */ // GameSyncSave
|
||||
/* 51: 22000-22C84, 00C84 */ // PSS Icon (bool32 data present, 40x40 u16 pic, unused)
|
||||
/* 52: 22E00-23428, 00628 */ // ValidationSave (updatabale Public Key for legal check api calls)
|
||||
/* 53: 23600-23A00, 00400 */ Contest = 0x23600;
|
||||
/* 54: 23A00-2B4D0, 07AD0 */ SecretBase = 0x23A00;
|
||||
/* 55: 2B600-32EB0, 078B0 */ EonTicket = 0x319B8;
|
||||
/* 56: 33000-67AD0, 34AD0 */ Box = 0x33000;
|
||||
/* 57: 67C00-75C58, 0E058 */ JPEG = 0x67C00;
|
||||
|
||||
Items = new MyItem6XY(this, 0x00400);
|
||||
PuffBlock = new Puff6(this, 0x0000);
|
||||
GameTime = new GameTime6(this, 0x01200);
|
||||
Situation = new Situation6(this, 0x01400);
|
||||
Played = new PlayTime6(this, 0x01800);
|
||||
BoxLayout = new BoxLayout6(this, 0x04400);
|
||||
Status = new MyStatus6(this, 0x14000);
|
||||
Zukan = new Zukan6(this, 0x15000, 0x15000 + 0x400);
|
||||
OPowerBlock = new OPower6(this, 0x17400);
|
||||
MysteryBlock = new MysteryBlock6(this, 0x1CC00);
|
||||
Records = new Record6(this, 0x1F400, Core.Records.MaxType_AO);
|
||||
Sango = new SangoInfoBlock(this, 0x2B600);
|
||||
|
||||
EventFlag = EventConst + 0x2FC;
|
||||
PokeDexLanguageFlags = PokeDex + 0x400;
|
||||
Spinda = PokeDex + 0x680;
|
||||
EncounterCount = PokeDex + 0x686;
|
||||
WondercardData = WondercardFlags + 0x100;
|
||||
Daycare2 = Daycare + 0x1F0;
|
||||
|
||||
HeldItems = Legal.HeldItem_XY;
|
||||
Personal = PersonalTable.XY;
|
||||
}
|
||||
|
||||
public int EonTicket { get; private set; } = int.MinValue;
|
||||
public int Contest { get; private set; } = int.MinValue;
|
||||
|
||||
public Zukan6 Zukan { get; private set; }
|
||||
public Puff6 PuffBlock { get; private set; }
|
||||
public OPower6 OPowerBlock { get; private set; }
|
||||
public BoxLayout6 BoxLayout { get; private set; }
|
||||
public MysteryBlock6 MysteryBlock { get; private set; }
|
||||
public SangoInfoBlock Sango { get; set; }
|
||||
|
||||
public uint GetEncounterCount(int index) { return BitConverter.ToUInt16(Data, EncounterCount + (2 * index)); }
|
||||
public void SetEncounterCount(int index, ushort value) { BitConverter.GetBytes(value).CopyTo(Data, EncounterCount + (2 * index)); }
|
||||
|
||||
public override GameVersion Version
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Game)
|
||||
{
|
||||
case (int)GameVersion.AS: return GameVersion.AS;
|
||||
case (int)GameVersion.OR: return GameVersion.OR;
|
||||
}
|
||||
return GameVersion.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool GetCaught(int species) => Zukan.GetCaught(species);
|
||||
public override bool GetSeen(int species) => Zukan.GetSeen(species);
|
||||
public override void SetSeen(int species, bool seen) => Zukan.SetSeen(species, seen);
|
||||
public override void SetCaught(int species, bool caught) => Zukan.SetCaught(species, caught);
|
||||
|
||||
protected override void SetDex(PKM pkm)
|
||||
{
|
||||
Zukan.SetDex(pkm);
|
||||
int index = pkm.Species - 1;
|
||||
if ((uint)index >= (uint)MaxSpeciesID)
|
||||
return;
|
||||
|
||||
// Set DexNav count (only if not encountered previously)
|
||||
if (GetEncounterCount(index) == 0)
|
||||
SetEncounterCount(index, 1);
|
||||
}
|
||||
|
||||
// Daycare
|
||||
public override int DaycareSeedSize => 16;
|
||||
public override bool HasTwoDaycares => true;
|
||||
|
||||
public override int GetDaycareSlotOffset(int loc, int slot)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs < 0)
|
||||
return -1;
|
||||
return ofs + 8 + (slot * (SIZE_STORED + 8));
|
||||
}
|
||||
|
||||
public override uint? GetDaycareEXP(int loc, int slot)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs > -1)
|
||||
return BitConverter.ToUInt32(Data, ofs + ((SIZE_STORED + 8) * slot) + 4);
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool? IsDaycareOccupied(int loc, int slot)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs > -1)
|
||||
return Data[ofs + ((SIZE_STORED + 8) * slot)] == 1;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string GetDaycareRNGSeed(int loc)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs <= 0)
|
||||
return null;
|
||||
|
||||
var data = Data.Skip(ofs + 0x1E8).Take(DaycareSeedSize / 2).Reverse().ToArray();
|
||||
return BitConverter.ToString(data).Replace("-", string.Empty);
|
||||
}
|
||||
|
||||
public override bool? IsDaycareHasEgg(int loc)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs > -1)
|
||||
return Data[ofs + 0x1E0] == 1;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void SetDaycareEXP(int loc, int slot, uint EXP)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs > -1)
|
||||
BitConverter.GetBytes(EXP).CopyTo(Data, ofs + ((SIZE_STORED + 8) * slot) + 4);
|
||||
}
|
||||
|
||||
public override void SetDaycareOccupied(int loc, int slot, bool occupied)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs > -1)
|
||||
Data[ofs + ((SIZE_STORED + 8) * slot)] = (byte)(occupied ? 1 : 0);
|
||||
}
|
||||
|
||||
public override void SetDaycareRNGSeed(int loc, string seed)
|
||||
{
|
||||
if (loc != 0)
|
||||
return;
|
||||
if (Daycare < 0)
|
||||
return;
|
||||
if (seed == null)
|
||||
return;
|
||||
if (seed.Length > DaycareSeedSize)
|
||||
return;
|
||||
|
||||
Util.GetBytesFromHexString(seed).CopyTo(Data, Daycare + 0x1E8);
|
||||
}
|
||||
|
||||
public override void SetDaycareHasEgg(int loc, bool hasEgg)
|
||||
{
|
||||
int ofs = loc == 0 ? Daycare : Daycare2;
|
||||
if (ofs > -1)
|
||||
Data[ofs + 0x1E0] = (byte)(hasEgg ? 1 : 0);
|
||||
}
|
||||
|
||||
public override string JPEGTitle => HasJPPEGData ? string.Empty : Util.TrimFromZero(Encoding.Unicode.GetString(Data, JPEG, 0x1A));
|
||||
public override byte[] JPEGData => HasJPPEGData ? Array.Empty<byte>() : GetData(JPEG + 0x54, 0xE004);
|
||||
|
||||
private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF;
|
||||
|
||||
protected override bool[] MysteryGiftReceivedFlags { get => MysteryBlock.MysteryGiftReceivedFlags; set => MysteryBlock.MysteryGiftReceivedFlags = value; }
|
||||
protected override MysteryGift[] MysteryGiftCards { get => MysteryBlock.MysteryGiftCards; set => MysteryBlock.MysteryGiftCards = value; }
|
||||
|
||||
// Gym History
|
||||
public ushort[][] GymTeams
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SUBE < 0 || ORASDEMO)
|
||||
return Array.Empty<ushort[]>(); // no gym data
|
||||
|
||||
const int teamsize = 2 * 6; // 2byte/species, 6species/team
|
||||
const int size = teamsize * 8; // 8 gyms
|
||||
int ofs = SUBE - size - 4;
|
||||
|
||||
var data = GetData(ofs, size);
|
||||
ushort[][] teams = new ushort[8][];
|
||||
for (int i = 0; i < teams.Length; i++)
|
||||
Buffer.BlockCopy(data, teamsize * i, teams[i] = new ushort[6], 0, teamsize);
|
||||
return teams;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SUBE < 0 || ORASDEMO)
|
||||
return; // no gym data
|
||||
|
||||
const int teamsize = 2 * 6; // 2byte/species, 6species/team
|
||||
const int size = teamsize * 8; // 8 gyms
|
||||
int ofs = SUBE - size - 4;
|
||||
|
||||
byte[] data = new byte[size];
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
Buffer.BlockCopy(value[i], 0, data, teamsize * i, teamsize);
|
||||
SetData(data, ofs);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] LinkBlock
|
||||
{
|
||||
get => GetData(LinkInfo, 0xC48);
|
||||
set
|
||||
{
|
||||
if (value.Length != 0xC48)
|
||||
throw new ArgumentException(nameof(value));
|
||||
SetData(value, LinkInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public override int CurrentBox { get => BoxLayout.CurrentBox; set => BoxLayout.CurrentBox = value; }
|
||||
protected override int GetBoxWallpaperOffset(int box) => BoxLayout.GetBoxWallpaperOffset(box);
|
||||
public override int BoxesUnlocked { get => BoxLayout.BoxesUnlocked; set => BoxLayout.BoxesUnlocked = value; }
|
||||
public override byte[] BoxFlags { get => BoxLayout.BoxFlags; set => BoxLayout.BoxFlags = value; }
|
||||
}
|
||||
}
|
83
PKHeX.Core/Saves/SAV6AODemo.cs
Normal file
83
PKHeX.Core/Saves/SAV6AODemo.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Generation 6 <see cref="SaveFile"/> object for <see cref="GameVersion.ORASDEMO"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="SAV6" />
|
||||
public sealed class SAV6AODemo : SAV6
|
||||
{
|
||||
public SAV6AODemo(byte[] data) : base(data, BlocksAODemo, boAOdemo) => Initialize();
|
||||
public SAV6AODemo() : base(SaveUtil.SIZE_G6ORASDEMO, BlocksAODemo, boAOdemo) => Initialize();
|
||||
public override SaveFile Clone() => new SAV6AODemo((byte[])Data.Clone());
|
||||
public override int MaxMoveID => Legal.MaxMoveID_6_AO;
|
||||
public override int MaxItemID => Legal.MaxItemID_6_AO;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_6_AO;
|
||||
|
||||
private const int boAOdemo = SaveUtil.SIZE_G6ORASDEMO - 0x200;
|
||||
|
||||
public static readonly BlockInfo[] BlocksAODemo =
|
||||
{
|
||||
new BlockInfo6 (boAOdemo, 00, 0x00000, 0x00B90),
|
||||
new BlockInfo6 (boAOdemo, 01, 0x00C00, 0x0002C),
|
||||
new BlockInfo6 (boAOdemo, 02, 0x00E00, 0x00038),
|
||||
new BlockInfo6 (boAOdemo, 03, 0x01000, 0x00150),
|
||||
new BlockInfo6 (boAOdemo, 04, 0x01200, 0x00004),
|
||||
new BlockInfo6 (boAOdemo, 05, 0x01400, 0x00008),
|
||||
new BlockInfo6 (boAOdemo, 06, 0x01600, 0x00024),
|
||||
new BlockInfo6 (boAOdemo, 07, 0x01800, 0x02100),
|
||||
new BlockInfo6 (boAOdemo, 08, 0x03A00, 0x00130),
|
||||
new BlockInfo6 (boAOdemo, 09, 0x03C00, 0x00170),
|
||||
new BlockInfo6 (boAOdemo, 10, 0x03E00, 0x0061C),
|
||||
new BlockInfo6 (boAOdemo, 11, 0x04600, 0x00504),
|
||||
new BlockInfo6 (boAOdemo, 12, 0x04C00, 0x00004),
|
||||
new BlockInfo6 (boAOdemo, 13, 0x04E00, 0x00048),
|
||||
new BlockInfo6 (boAOdemo, 14, 0x05000, 0x00400),
|
||||
new BlockInfo6 (boAOdemo, 15, 0x05400, 0x0025C),
|
||||
};
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
/* 00: */ // MyItem = 0x00000; // MyItem // Bag
|
||||
/* 01: */ // ItemInfo = 0x00C00; // ItemInfo6
|
||||
/* 02: */ // GameTime = 0x00E00; // GameTime
|
||||
/* 03: */ // Trainer1 = 0x01000; // Situation
|
||||
/* 04: */ // = 0x01200; // [00004] RandomGroup (rand seeds)
|
||||
/* 05: */ // PlayTime = 0x01400; // PlayTime
|
||||
/* 06: */ // = 0x01600; // [00024] temp variables (u32 id + 32 u8)
|
||||
/* 07: */ // = 0x01800; // [02100] FieldMoveModelSave
|
||||
/* 08: */ Trainer2 = 0x03A00; // Misc
|
||||
/* 09: */ // = 0x03C00; // MyStatus
|
||||
/* 10: */ Party = 0x03E00; // PokePartySave
|
||||
/* 11: */ EventConst = 0x04600; // EventWork
|
||||
/* 12: */ // = 0x04C00; // [00004] Packed Menu Bits
|
||||
/* 13: */ // = 0x04E00; // [00048] Repel Info, (Swarm?) and other overworld info (roamer)
|
||||
/* 14: */ SUBE = 0x05000; // PokeDiarySave
|
||||
/* 15: */ // Record = 0x05400; // Record
|
||||
|
||||
Items = new MyItem6AO( this, 0x00000);
|
||||
ItemInfo = new ItemInfo6( this, 0x00C00);
|
||||
GameTime = new GameTime6( this, 0x00E00);
|
||||
Situation = new Situation6(this, 0x01000);
|
||||
Played = new PlayTime6( this, 0x01400);
|
||||
Status = new MyStatus6( this, 0x03C00);
|
||||
Records = new Record6(this, 0x05400, Core.Records.MaxType_AO);
|
||||
EventFlag = EventConst + 0x2FC;
|
||||
|
||||
HeldItems = Legal.HeldItem_AO;
|
||||
Personal = PersonalTable.AO;
|
||||
}
|
||||
|
||||
public override GameVersion Version
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Game)
|
||||
{
|
||||
case (int)GameVersion.AS: return GameVersion.AS;
|
||||
case (int)GameVersion.OR: return GameVersion.OR;
|
||||
}
|
||||
return GameVersion.Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
305
PKHeX.Core/Saves/SAV6XY.cs
Normal file
305
PKHeX.Core/Saves/SAV6XY.cs
Normal file
|
@ -0,0 +1,305 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Generation 6 <see cref="SaveFile"/> object for <see cref="GameVersion.XY"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="SAV6" />
|
||||
public sealed class SAV6XY : SAV6, IPokePuff, IOPower, ILink
|
||||
{
|
||||
public SAV6XY(byte[] data) : base(data, BlocksXY, boXY) => Initialize();
|
||||
public SAV6XY() : base(SaveUtil.SIZE_G6XY, BlocksXY, boXY) => Initialize();
|
||||
public override SaveFile Clone() => new SAV6XY((byte[])Data.Clone());
|
||||
public override int MaxMoveID => Legal.MaxMoveID_6_XY;
|
||||
public override int MaxItemID => Legal.MaxItemID_6_XY;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_6_XY;
|
||||
|
||||
private const int boXY = SaveUtil.SIZE_G6XY - 0x200;
|
||||
|
||||
public static readonly BlockInfo[] BlocksXY =
|
||||
{
|
||||
new BlockInfo6(boXY, 00, 0x00000, 0x002C8),
|
||||
new BlockInfo6(boXY, 01, 0x00400, 0x00B88),
|
||||
new BlockInfo6(boXY, 02, 0x01000, 0x0002C),
|
||||
new BlockInfo6(boXY, 03, 0x01200, 0x00038),
|
||||
new BlockInfo6(boXY, 04, 0x01400, 0x00150),
|
||||
new BlockInfo6(boXY, 05, 0x01600, 0x00004),
|
||||
new BlockInfo6(boXY, 06, 0x01800, 0x00008),
|
||||
new BlockInfo6(boXY, 07, 0x01A00, 0x001C0),
|
||||
new BlockInfo6(boXY, 08, 0x01C00, 0x000BE),
|
||||
new BlockInfo6(boXY, 09, 0x01E00, 0x00024),
|
||||
new BlockInfo6(boXY, 10, 0x02000, 0x02100),
|
||||
new BlockInfo6(boXY, 11, 0x04200, 0x00140),
|
||||
new BlockInfo6(boXY, 12, 0x04400, 0x00440),
|
||||
new BlockInfo6(boXY, 13, 0x04A00, 0x00574),
|
||||
new BlockInfo6(boXY, 14, 0x05000, 0x04E28),
|
||||
new BlockInfo6(boXY, 15, 0x0A000, 0x04E28),
|
||||
new BlockInfo6(boXY, 16, 0x0F000, 0x04E28),
|
||||
new BlockInfo6(boXY, 17, 0x14000, 0x00170),
|
||||
new BlockInfo6(boXY, 18, 0x14200, 0x0061C),
|
||||
new BlockInfo6(boXY, 19, 0x14A00, 0x00504),
|
||||
new BlockInfo6(boXY, 20, 0x15000, 0x006A0),
|
||||
new BlockInfo6(boXY, 21, 0x15800, 0x00644),
|
||||
new BlockInfo6(boXY, 22, 0x16000, 0x00104),
|
||||
new BlockInfo6(boXY, 23, 0x16200, 0x00004),
|
||||
new BlockInfo6(boXY, 24, 0x16400, 0x00420),
|
||||
new BlockInfo6(boXY, 25, 0x16A00, 0x00064),
|
||||
new BlockInfo6(boXY, 26, 0x16C00, 0x003F0),
|
||||
new BlockInfo6(boXY, 27, 0x17000, 0x0070C),
|
||||
new BlockInfo6(boXY, 28, 0x17800, 0x00180),
|
||||
new BlockInfo6(boXY, 29, 0x17A00, 0x00004),
|
||||
new BlockInfo6(boXY, 30, 0x17C00, 0x0000C),
|
||||
new BlockInfo6(boXY, 31, 0x17E00, 0x00048),
|
||||
new BlockInfo6(boXY, 32, 0x18000, 0x00054),
|
||||
new BlockInfo6(boXY, 33, 0x18200, 0x00644),
|
||||
new BlockInfo6(boXY, 34, 0x18A00, 0x005C8),
|
||||
new BlockInfo6(boXY, 35, 0x19000, 0x002F8),
|
||||
new BlockInfo6(boXY, 36, 0x19400, 0x01B40),
|
||||
new BlockInfo6(boXY, 37, 0x1B000, 0x001F4),
|
||||
new BlockInfo6(boXY, 38, 0x1B200, 0x001F0),
|
||||
new BlockInfo6(boXY, 39, 0x1B400, 0x00216),
|
||||
new BlockInfo6(boXY, 40, 0x1B800, 0x00390),
|
||||
new BlockInfo6(boXY, 41, 0x1BC00, 0x01A90),
|
||||
new BlockInfo6(boXY, 42, 0x1D800, 0x00308),
|
||||
new BlockInfo6(boXY, 43, 0x1DC00, 0x00618),
|
||||
new BlockInfo6(boXY, 44, 0x1E400, 0x0025C),
|
||||
new BlockInfo6(boXY, 45, 0x1E800, 0x00834),
|
||||
new BlockInfo6(boXY, 46, 0x1F200, 0x00318),
|
||||
new BlockInfo6(boXY, 47, 0x1F600, 0x007D0),
|
||||
new BlockInfo6(boXY, 48, 0x1FE00, 0x00C48),
|
||||
new BlockInfo6(boXY, 49, 0x20C00, 0x00078),
|
||||
new BlockInfo6(boXY, 50, 0x20E00, 0x00200),
|
||||
new BlockInfo6(boXY, 51, 0x21000, 0x00C84),
|
||||
new BlockInfo6(boXY, 52, 0x21E00, 0x00628),
|
||||
new BlockInfo6(boXY, 53, 0x22600, 0x34AD0),
|
||||
new BlockInfo6(boXY, 54, 0x57200, 0x0E058),
|
||||
};
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
/* 00: 00000-002C8, 002C8 */ // Puff = 0x00000;
|
||||
/* 01: 00400-00F88, 00B88 */ // MyItem = 0x00400; // Bag
|
||||
/* 02: 01000-0102C, 0002C */ // ItemInfo = 0x1000; // Select Bound Items
|
||||
/* 03: 01200-01238, 00038 */ // GameTime = 0x01200;
|
||||
/* 04: 01400-01550, 00150 */ Trainer1 = 0x1400; // Situation
|
||||
/* 05: 01600-01604, 00004 */ // RandomGroup (rand seeds)
|
||||
/* 06: 01800-01808, 00008 */ PlayTime = 0x1800; // PlayTime
|
||||
/* 07: 01A00-01BC0, 001C0 */ Accessories = 0x1A00; // Fashion
|
||||
/* 08: 01C00-01CBE, 000BE */ // amie minigame records
|
||||
/* 09: 01E00-01E24, 00024 */ // temp variables (u32 id + 32 u8)
|
||||
/* 10: 02000-04100, 02100 */ // FieldMoveModelSave
|
||||
/* 11: 04200-04340, 00140 */ Trainer2 = 0x4200; // Misc
|
||||
/* 12: 04400-04840, 00440 */ PCLayout = 0x4400; // BOX
|
||||
/* 13: 04A00-04F74, 00574 */ BattleBox = 0x04A00; // BattleBox
|
||||
/* 14: 05000-09E28, 04E28 */ PSS = 0x05000;
|
||||
/* 15: 0A000-0EE28, 04E28 */ // PSS2
|
||||
/* 16: 0F000-13E28, 04E28 */ // PSS3
|
||||
/* 17: 14000-14170, 00170 */ // MyStatus
|
||||
/* 18: 14200-1481C, 0061C */ Party = 0x14200; // PokePartySave
|
||||
/* 19: 14A00-14F04, 00504 */ EventConst = 0x14A00; // EventWork
|
||||
/* 20: 15000-156A0, 006A0 */ PokeDex = 0x15000; // ZukanData
|
||||
/* 21: 15800-15E44, 00644 */ // hologram clips
|
||||
/* 22: 16000-16104, 00104 */ Fused = 0x16000; // UnionPokemon
|
||||
/* 23: 16200-16204, 00004 */ // ConfigSave
|
||||
/* 24: 16400-16820, 00420 */ // Amie decoration stuff
|
||||
/* 25: 16A00-16A64, 00064 */ // OPower = 0x16A00;
|
||||
/* 26: 16C00-16FF0, 003F0 */ // Strength Rock position (xyz float: 84 entries, 12bytes/entry)
|
||||
/* 27: 17000-1770C, 0070C */ // Trainer PR Video
|
||||
/* 28: 17800-17980, 00180 */ GTS = 0x17800; // GtsData
|
||||
/* 29: 17A00-17A04, 00004 */ // Packed Menu Bits
|
||||
/* 30: 17C00-17C0C, 0000C */ // PSS Profile Q&A (6*questions, 6*answer)
|
||||
/* 31: 17E00-17E48, 00048 */ // Repel Info, (Swarm?) and other overworld info (roamer)
|
||||
/* 32: 18000-18054, 00054 */ // BOSS data fetch history (serial/mystery gift), 4byte intro & 20*4byte entries
|
||||
/* 33: 18200-18844, 00644 */ // Streetpass history (4 byte intro, 20*4byte entries, 20*76 byte entries)
|
||||
/* 34: 18A00-18FC8, 005C8 */ // LiveMatchData/BattleSpotData
|
||||
/* 35: 19000-192F8, 002F8 */ // MAC Address & Network Connection Logging (0x98 per entry, 5 entries)
|
||||
/* 36: 19400-1AF40, 01B40 */ HoF = 0x19400; // Dendou
|
||||
/* 37: 1B000-1B1F4, 001F4 */ MaisonStats = 0x1B1C0; // BattleInstSave
|
||||
/* 38: 1B200-1B3F0, 001F0 */ Daycare = 0x1B200; // Sodateya
|
||||
/* 39: 1B400-1B616, 00216 */ // BattleInstSave
|
||||
/* 40: 1B800-1BB90, 00390 */ BerryField = 0x1B800;
|
||||
/* 41: 1BC00-1D690, 01A90 */ WondercardFlags = 0x1BC00; // MysteryGiftSave
|
||||
/* 42: 1D800-1DB08, 00308 */ SUBE = 0x1D890; // PokeDiarySave
|
||||
/* 43: 1DC00-1E218, 00618 */ // Storyline Records
|
||||
/* 44: 1E400-1E65C, 0025C */ // Record = 0x1E400;
|
||||
/* 45: 1E800-1F034, 00834 */ // Friend Safari (0x15 per entry, 100 entries)
|
||||
/* 46: 1F200-1F518, 00318 */ SuperTrain = 0x1F200;
|
||||
/* 47: 1F600-1FDD0, 007D0 */ // Unused (lmao)
|
||||
/* 48: 1FE00-20A48, 00C48 */ LinkInfo = 0x1FE00;
|
||||
/* 49: 20C00-20C78, 00078 */ // PSS usage info
|
||||
/* 50: 20E00-21000, 00200 */ // GameSyncSave
|
||||
/* 51: 21000-21C84, 00C84 */ // PSS Icon (bool32 data present, 40x40 u16 pic, unused)
|
||||
/* 52: 21E00-22428, 00628 */ // ValidationSave (updatabale Public Key for legal check api calls)
|
||||
/* 53: 22600-570D0, 34AD0 */ Box = 0x22600;
|
||||
/* 54: 57200-65258, 0E058 */ JPEG = 0x57200;
|
||||
|
||||
Items = new MyItem6XY(this, 0x00400);
|
||||
PuffBlock = new Puff6(this, 0x00000);
|
||||
GameTime = new GameTime6(this, 0x01200);
|
||||
Situation = new Situation6(this, 0x01400);
|
||||
Played = new PlayTime6(this, 0x01800);
|
||||
BoxLayout = new BoxLayout6(this, 0x4400);
|
||||
Status = new MyStatus6XY(this, 0x14000);
|
||||
Zukan = new Zukan6(this, 0x15000, 0x15000 + 0x3C8);
|
||||
OPowerBlock = new OPower6(this, 0x16A00);
|
||||
MysteryBlock = new MysteryBlock6(this, 0x1BC00);
|
||||
Records = new Record6(this, 0x1E400, Core.Records.MaxType_XY);
|
||||
|
||||
EventFlag = EventConst + 0x2FC;
|
||||
PokeDexLanguageFlags = PokeDex + 0x3C8;
|
||||
Spinda = PokeDex + 0x648;
|
||||
WondercardData = WondercardFlags + 0x100;
|
||||
|
||||
HeldItems = Legal.HeldItem_XY;
|
||||
Personal = PersonalTable.XY;
|
||||
}
|
||||
|
||||
public Zukan6 Zukan { get; private set; }
|
||||
public Puff6 PuffBlock { get; private set; }
|
||||
public OPower6 OPowerBlock { get; private set; }
|
||||
public BoxLayout6 BoxLayout { get; private set; }
|
||||
public MysteryBlock6 MysteryBlock { get; private set; }
|
||||
|
||||
protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm);
|
||||
|
||||
// Daycare
|
||||
public override int DaycareSeedSize => 16;
|
||||
public override bool HasTwoDaycares => false;
|
||||
public override bool? IsDaycareOccupied(int loc, int slot) => Data[Daycare + 0 + ((SIZE_STORED + 8) * slot)] == 1;
|
||||
public override uint? GetDaycareEXP(int loc, int slot) => BitConverter.ToUInt32(Data, Daycare + 4 + ((SIZE_STORED + 8) * slot));
|
||||
|
||||
public override int GetDaycareSlotOffset(int loc, int slot) => Daycare + 8 + (slot * (SIZE_STORED + 8));
|
||||
public override bool? IsDaycareHasEgg(int loc) => Data[Daycare + 0x1E0] == 1;
|
||||
public override void SetDaycareHasEgg(int loc, bool hasEgg) => Data[Daycare + 0x1E0] = (byte)(hasEgg ? 1 : 0);
|
||||
public override void SetDaycareOccupied(int loc, int slot, bool occupied) => Data[Daycare + ((SIZE_STORED + 8) * slot)] = (byte)(occupied ? 1 : 0);
|
||||
public override void SetDaycareEXP(int loc, int slot, uint EXP) => BitConverter.GetBytes(EXP).CopyTo(Data, Daycare + 4 + ((SIZE_STORED + 8) * slot));
|
||||
|
||||
public override void SetDaycareRNGSeed(int loc, string seed)
|
||||
{
|
||||
if (loc != 0)
|
||||
return;
|
||||
if (Daycare < 0)
|
||||
return;
|
||||
if (seed == null)
|
||||
return;
|
||||
if (seed.Length > DaycareSeedSize)
|
||||
return;
|
||||
|
||||
Util.GetBytesFromHexString(seed).CopyTo(Data, Daycare + 0x1E8);
|
||||
}
|
||||
|
||||
public override string JPEGTitle => HasJPPEGData ? string.Empty : Util.TrimFromZero(Encoding.Unicode.GetString(Data, JPEG, 0x1A));
|
||||
public override byte[] JPEGData => HasJPPEGData ? Array.Empty<byte>() : GetData(JPEG + 0x54, 0xE004);
|
||||
|
||||
private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF;
|
||||
|
||||
// Gym History
|
||||
public ushort[][] GymTeams
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SUBE < 0 || ORASDEMO)
|
||||
return Array.Empty<ushort[]>(); // no gym data
|
||||
|
||||
const int teamsize = 2 * 6; // 2byte/species, 6species/team
|
||||
const int size = teamsize * 8; // 8 gyms
|
||||
int ofs = SUBE - size - 4;
|
||||
|
||||
var data = GetData(ofs, size);
|
||||
ushort[][] teams = new ushort[8][];
|
||||
for (int i = 0; i < teams.Length; i++)
|
||||
Buffer.BlockCopy(data, teamsize * i, teams[i] = new ushort[6], 0, teamsize);
|
||||
return teams;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SUBE < 0 || ORASDEMO)
|
||||
return; // no gym data
|
||||
|
||||
const int teamsize = 2 * 6; // 2byte/species, 6species/team
|
||||
const int size = teamsize * 8; // 8 gyms
|
||||
int ofs = SUBE - size - 4;
|
||||
|
||||
byte[] data = new byte[size];
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
Buffer.BlockCopy(value[i], 0, data, teamsize * i, teamsize);
|
||||
SetData(data, ofs);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnlockAllFriendSafariSlots()
|
||||
{
|
||||
if (!XY)
|
||||
return;
|
||||
|
||||
// Unlock + reveal all safari slots if friend data is present
|
||||
const int start = 0x1E7FF;
|
||||
const int size = 0x15;
|
||||
for (int i = 1; i < 101; i++)
|
||||
{
|
||||
int ofs = start + (i * size);
|
||||
if (Data[ofs] != 0) // no friend data == 0x00
|
||||
Data[ofs] = 0x3D;
|
||||
}
|
||||
Edited = true;
|
||||
}
|
||||
|
||||
public void UnlockAllAccessories()
|
||||
{
|
||||
if (!XY)
|
||||
return;
|
||||
|
||||
SetData(AllAccessories, Accessories);
|
||||
}
|
||||
|
||||
private static readonly byte[] AllAccessories =
|
||||
{
|
||||
0xFE,0xFF,0xFF,0x7E,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xEF,0xFF,0xFF,0xFF,0xF9,0xFF,0xFB,0xFF,0xF7,0xFF,0xFF,0x0F,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,
|
||||
0xFF,0x7E,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,
|
||||
0xFF,0xFF,0xFF,0xF9,0xFF,0xFB,0xFF,0xF7,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
|
||||
public override GameVersion Version
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Game)
|
||||
{
|
||||
case (int)GameVersion.X: return GameVersion.X;
|
||||
case (int)GameVersion.Y: return GameVersion.Y;
|
||||
}
|
||||
return GameVersion.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool[] MysteryGiftReceivedFlags { get => MysteryBlock.MysteryGiftReceivedFlags; set => MysteryBlock.MysteryGiftReceivedFlags = value; }
|
||||
protected override MysteryGift[] MysteryGiftCards { get => MysteryBlock.MysteryGiftCards; set => MysteryBlock.MysteryGiftCards = value; }
|
||||
|
||||
public byte[] LinkBlock
|
||||
{
|
||||
get => GetData(LinkInfo, 0xC48);
|
||||
set
|
||||
{
|
||||
if (value.Length != 0xC48)
|
||||
throw new ArgumentException(nameof(value));
|
||||
value.CopyTo(Data, LinkInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool GetCaught(int species) => Zukan.GetCaught(species);
|
||||
public override bool GetSeen(int species) => Zukan.GetSeen(species);
|
||||
public override void SetSeen(int species, bool seen) => Zukan.SetSeen(species, seen);
|
||||
public override void SetCaught(int species, bool caught) => Zukan.SetCaught(species, caught);
|
||||
|
||||
public override int CurrentBox { get => BoxLayout.CurrentBox; set => BoxLayout.CurrentBox = value; }
|
||||
protected override int GetBoxWallpaperOffset(int box) => BoxLayout.GetBoxWallpaperOffset(box);
|
||||
public override int BoxesUnlocked { get => BoxLayout.BoxesUnlocked; set => BoxLayout.BoxesUnlocked = value; }
|
||||
public override byte[] BoxFlags { get => BoxLayout.BoxFlags; set => BoxLayout.BoxFlags = value; }
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
47
PKHeX.Core/Saves/SAV7BlockIndex.cs
Normal file
47
PKHeX.Core/Saves/SAV7BlockIndex.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public enum SAV7BlockIndex
|
||||
{
|
||||
MyItem,
|
||||
Situation,
|
||||
RandomGroup,
|
||||
MyStatus,
|
||||
PokePartySave,
|
||||
EventWork,
|
||||
ZukanData,
|
||||
GtsData,
|
||||
UnionPokemon,
|
||||
Misc,
|
||||
FieldMenu,
|
||||
ConfigSave,
|
||||
GameTime,
|
||||
BOX,
|
||||
BoxPokemon,
|
||||
ResortSave,
|
||||
PlayTime,
|
||||
FieldMoveModelSave,
|
||||
Fashion,
|
||||
JoinFestaPersonalSave1,
|
||||
JoinFestaPersonalSave2,
|
||||
JoinFestaDataSave,
|
||||
BerrySpot,
|
||||
FishingSpot,
|
||||
LiveMatchData,
|
||||
BattleSpotData,
|
||||
PokeFinderSave,
|
||||
MysteryGiftSave,
|
||||
Record,
|
||||
ValidationSave,
|
||||
GameSyncSave,
|
||||
PokeDiarySave,
|
||||
BattleInstSave,
|
||||
Sodateya,
|
||||
WeatherSave,
|
||||
QRReaderSaveData,
|
||||
TurtleSalmonSave,
|
||||
|
||||
// Ultra Sun/Ultra Moon only
|
||||
BattleFesSave,
|
||||
FinderStudioSave,
|
||||
}
|
||||
}
|
68
PKHeX.Core/Saves/SAV7SM.cs
Normal file
68
PKHeX.Core/Saves/SAV7SM.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public class SAV7SM : SAV7
|
||||
{
|
||||
public SAV7SM(byte[] data) : base(data, BlocksSM, boSM) => Initialize();
|
||||
public SAV7SM() : base(SaveUtil.SIZE_G7SM, BlocksSM, boSM) => Initialize();
|
||||
public override SaveFile Clone() => new SAV7SM((byte[])Data.Clone());
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Personal = PersonalTable.SM;
|
||||
HeldItems = Legal.HeldItems_SM;
|
||||
|
||||
Items = new MyItem7SM(this, Bag);
|
||||
Zukan = new Zukan7(this, PokeDex, PokeDexLanguageFlags);
|
||||
Records = new Record6(this, Record, Core.Records.MaxType_SM);
|
||||
}
|
||||
|
||||
protected override int EventFlagMax => 3968;
|
||||
public override int MaxMoveID => Legal.MaxMoveID_7;
|
||||
public override int MaxSpeciesID => Legal.MaxSpeciesID_7;
|
||||
public override int MaxItemID => Legal.MaxItemID_7;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_7;
|
||||
|
||||
private const int boSM = SaveUtil.SIZE_G7SM - 0x200;
|
||||
|
||||
public static readonly BlockInfo[] BlocksSM =
|
||||
{
|
||||
new BlockInfo7 (boSM, 00, 0x00000, 0x00DE0),
|
||||
new BlockInfo7 (boSM, 01, 0x00E00, 0x0007C),
|
||||
new BlockInfo7 (boSM, 02, 0x01000, 0x00014),
|
||||
new BlockInfo7 (boSM, 03, 0x01200, 0x000C0),
|
||||
new BlockInfo7 (boSM, 04, 0x01400, 0x0061C),
|
||||
new BlockInfo7 (boSM, 05, 0x01C00, 0x00E00),
|
||||
new BlockInfo7 (boSM, 06, 0x02A00, 0x00F78),
|
||||
new BlockInfo7 (boSM, 07, 0x03A00, 0x00228),
|
||||
new BlockInfo7 (boSM, 08, 0x03E00, 0x00104),
|
||||
new BlockInfo7 (boSM, 09, 0x04000, 0x00200),
|
||||
new BlockInfo7 (boSM, 10, 0x04200, 0x00020),
|
||||
new BlockInfo7 (boSM, 11, 0x04400, 0x00004),
|
||||
new BlockInfo7 (boSM, 12, 0x04600, 0x00058),
|
||||
new BlockInfo7 (boSM, 13, 0x04800, 0x005E6),
|
||||
new BlockInfo7 (boSM, 14, 0x04E00, 0x36600),
|
||||
new BlockInfo7 (boSM, 15, 0x3B400, 0x0572C),
|
||||
new BlockInfo7 (boSM, 16, 0x40C00, 0x00008),
|
||||
new BlockInfo7 (boSM, 17, 0x40E00, 0x01080),
|
||||
new BlockInfo7 (boSM, 18, 0x42000, 0x01A08),
|
||||
new BlockInfo7 (boSM, 19, 0x43C00, 0x06408),
|
||||
new BlockInfo7 (boSM, 20, 0x4A200, 0x06408),
|
||||
new BlockInfo7 (boSM, 21, 0x50800, 0x03998),
|
||||
new BlockInfo7 (boSM, 22, 0x54200, 0x00100),
|
||||
new BlockInfo7 (boSM, 23, 0x54400, 0x00100),
|
||||
new BlockInfo7 (boSM, 24, 0x54600, 0x10528),
|
||||
new BlockInfo7 (boSM, 25, 0x64C00, 0x00204),
|
||||
new BlockInfo7 (boSM, 26, 0x65000, 0x00B60),
|
||||
new BlockInfo7 (boSM, 27, 0x65C00, 0x03F50),
|
||||
new BlockInfo7 (boSM, 28, 0x69C00, 0x00358),
|
||||
new BlockInfo7 (boSM, 29, 0x6A000, 0x00728),
|
||||
new BlockInfo7 (boSM, 30, 0x6A800, 0x00200),
|
||||
new BlockInfo7 (boSM, 31, 0x6AA00, 0x00718),
|
||||
new BlockInfo7 (boSM, 32, 0x6B200, 0x001FC),
|
||||
new BlockInfo7 (boSM, 33, 0x6B400, 0x00200),
|
||||
new BlockInfo7 (boSM, 34, 0x6B600, 0x00120),
|
||||
new BlockInfo7 (boSM, 35, 0x6B800, 0x001C8),
|
||||
new BlockInfo7 (boSM, 36, 0x6BA00, 0x00200),
|
||||
};
|
||||
}
|
||||
}
|
78
PKHeX.Core/Saves/SAV7USUM.cs
Normal file
78
PKHeX.Core/Saves/SAV7USUM.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public class SAV7USUM : SAV7
|
||||
{
|
||||
public SAV7USUM(byte[] data) : base(data, BlocksUSUM, boUU)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public SAV7USUM() : base(SaveUtil.SIZE_G7USUM, BlocksUSUM, boUU)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public override SaveFile Clone() => new SAV7USUM((byte[])Data.Clone());
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Personal = PersonalTable.USUM;
|
||||
HeldItems = Legal.HeldItems_USUM;
|
||||
|
||||
Items = new MyItem7USUM(this, Bag);
|
||||
Zukan = new Zukan7(this, PokeDex, PokeDexLanguageFlags);
|
||||
Records = new Record6(this, Record, Core.Records.MaxType_USUM);
|
||||
}
|
||||
|
||||
protected override int EventFlagMax => 4928;
|
||||
public override int MaxMoveID => Legal.MaxMoveID_7_USUM;
|
||||
public override int MaxSpeciesID => Legal.MaxSpeciesID_7_USUM;
|
||||
public override int MaxItemID => Legal.MaxItemID_7_USUM;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_7_USUM;
|
||||
|
||||
private const int boUU = SaveUtil.SIZE_G7USUM - 0x200;
|
||||
|
||||
public static readonly BlockInfo[] BlocksUSUM =
|
||||
{
|
||||
new BlockInfo7(boUU, 00, 0x00000, 0x00E28),
|
||||
new BlockInfo7(boUU, 01, 0x01000, 0x0007C),
|
||||
new BlockInfo7(boUU, 02, 0x01200, 0x00014),
|
||||
new BlockInfo7(boUU, 03, 0x01400, 0x000C0),
|
||||
new BlockInfo7(boUU, 04, 0x01600, 0x0061C),
|
||||
new BlockInfo7(boUU, 05, 0x01E00, 0x00E00),
|
||||
new BlockInfo7(boUU, 06, 0x02C00, 0x00F78),
|
||||
new BlockInfo7(boUU, 07, 0x03C00, 0x00228),
|
||||
new BlockInfo7(boUU, 08, 0x04000, 0x0030C),
|
||||
new BlockInfo7(boUU, 09, 0x04400, 0x001FC),
|
||||
new BlockInfo7(boUU, 10, 0x04600, 0x0004C),
|
||||
new BlockInfo7(boUU, 11, 0x04800, 0x00004),
|
||||
new BlockInfo7(boUU, 12, 0x04A00, 0x00058),
|
||||
new BlockInfo7(boUU, 13, 0x04C00, 0x005E6),
|
||||
new BlockInfo7(boUU, 14, 0x05200, 0x36600),
|
||||
new BlockInfo7(boUU, 15, 0x3B800, 0x0572C),
|
||||
new BlockInfo7(boUU, 16, 0x41000, 0x00008),
|
||||
new BlockInfo7(boUU, 17, 0x41200, 0x01218),
|
||||
new BlockInfo7(boUU, 18, 0x42600, 0x01A08),
|
||||
new BlockInfo7(boUU, 19, 0x44200, 0x06408),
|
||||
new BlockInfo7(boUU, 20, 0x4A800, 0x06408),
|
||||
new BlockInfo7(boUU, 21, 0x50E00, 0x03998),
|
||||
new BlockInfo7(boUU, 22, 0x54800, 0x00100),
|
||||
new BlockInfo7(boUU, 23, 0x54A00, 0x00100),
|
||||
new BlockInfo7(boUU, 24, 0x54C00, 0x10528),
|
||||
new BlockInfo7(boUU, 25, 0x65200, 0x00204),
|
||||
new BlockInfo7(boUU, 26, 0x65600, 0x00B60),
|
||||
new BlockInfo7(boUU, 27, 0x66200, 0x03F50),
|
||||
new BlockInfo7(boUU, 28, 0x6A200, 0x00358),
|
||||
new BlockInfo7(boUU, 29, 0x6A600, 0x00728),
|
||||
new BlockInfo7(boUU, 30, 0x6AE00, 0x00200),
|
||||
new BlockInfo7(boUU, 31, 0x6B000, 0x00718),
|
||||
new BlockInfo7(boUU, 32, 0x6B800, 0x001FC),
|
||||
new BlockInfo7(boUU, 33, 0x6BA00, 0x00200),
|
||||
new BlockInfo7(boUU, 34, 0x6BC00, 0x00120),
|
||||
new BlockInfo7(boUU, 35, 0x6BE00, 0x001C8),
|
||||
new BlockInfo7(boUU, 36, 0x6C000, 0x00200),
|
||||
new BlockInfo7(boUU, 37, 0x6C200, 0x0039C),
|
||||
new BlockInfo7(boUU, 38, 0x6C600, 0x00400),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
|
@ -8,7 +7,7 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Generation 7 <see cref="SaveFile"/> object for <see cref="GameVersion.GG"/> games.
|
||||
/// </summary>
|
||||
public sealed class SAV7b : SaveFile, ISecureValueStorage
|
||||
public sealed class SAV7b : SAV_BEEF
|
||||
{
|
||||
protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}";
|
||||
public override string Filter => "savedata|*.bin";
|
||||
|
@ -22,18 +21,19 @@ namespace PKHeX.Core
|
|||
|
||||
public override SaveFile Clone() => new SAV7b((byte[])Data.Clone());
|
||||
|
||||
public SAV7b() : this(new byte[SaveUtil.SIZE_G7GG]) { }
|
||||
|
||||
public SAV7b(byte[] data)
|
||||
public SAV7b() : base(SaveUtil.SIZE_G7GG, BlockInfoGG, 0xB8800)
|
||||
{
|
||||
Data = data;
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
// Load Info
|
||||
const int len = 0xB8800; // 1mb always allocated
|
||||
BlockInfoOffset = len - 0x1F0;
|
||||
Blocks = !Exportable ? BlockInfoGG : BlockInfo3DS.GetBlockInfoData(Data, ref BlockInfoOffset, Checksums.CRC16NoInvert, len);
|
||||
public SAV7b(byte[] data) : base(data, BlockInfoGG, 0xB8800)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Personal = PersonalTable.GG;
|
||||
|
||||
Box = GetBlockOffset(BelugaBlockIndex.PokeListPokemon);
|
||||
|
@ -53,23 +53,18 @@ namespace PKHeX.Core
|
|||
WondercardData = GiftRecords.Offset;
|
||||
|
||||
HeldItems = Legal.HeldItems_GG;
|
||||
|
||||
if (Exportable)
|
||||
CanReadChecksums();
|
||||
else
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
// Save Block accessors
|
||||
public readonly MyItem Items;
|
||||
public readonly Misc7b Misc;
|
||||
public readonly Zukan7b Zukan;
|
||||
public readonly MyStatus7b Status;
|
||||
public readonly PlayTime7b Played;
|
||||
public readonly ConfigSave7b Config;
|
||||
public readonly EventWork7b EventWork;
|
||||
public readonly PokeListHeader Storage;
|
||||
public readonly WB7Records GiftRecords;
|
||||
public MyItem Items { get; private set; }
|
||||
public Misc7b Misc { get; private set; }
|
||||
public Zukan7b Zukan { get; private set; }
|
||||
public MyStatus7b Status { get; private set; }
|
||||
public PlayTime7b Played { get; private set; }
|
||||
public ConfigSave7b Config { get; private set; }
|
||||
public EventWork7b EventWork { get; private set; }
|
||||
public PokeListHeader Storage { get; private set; }
|
||||
public WB7Records GiftRecords { get; private set; }
|
||||
|
||||
public override InventoryPouch[] Inventory { get => Items.Inventory; set => Items.Inventory = value; }
|
||||
|
||||
|
@ -98,54 +93,36 @@ namespace PKHeX.Core
|
|||
public override int BoxSlotCount => 25;
|
||||
public override int BoxCount => 40; // 1000/25
|
||||
|
||||
// Blocks & Offsets
|
||||
private readonly int BlockInfoOffset;
|
||||
public readonly BlockInfo[] Blocks;
|
||||
public override bool ChecksumsValid => CanReadChecksums() && Blocks.GetChecksumsValid(Data);
|
||||
public override string ChecksumInfo => CanReadChecksums() ? Blocks.GetChecksumInfo(Data) : string.Empty;
|
||||
|
||||
public BlockInfo GetBlock(BelugaBlockIndex index) => Blocks[(int)index >= Blocks.Length ? 0 : (int)index];
|
||||
public BlockInfo GetBlock(BelugaBlockIndex index) => Blocks[(int)index];
|
||||
public int GetBlockOffset(BelugaBlockIndex index) => GetBlock(index).Offset;
|
||||
|
||||
private const int boGG = 0xB8800; // nowhere near 1MB (savedata.bin size)
|
||||
|
||||
private static readonly BlockInfo[] BlockInfoGG =
|
||||
{
|
||||
new BlockInfo3DS {Offset = 0x00000, Length = 0x00D90},
|
||||
new BlockInfo3DS {Offset = 0x00E00, Length = 0x00200},
|
||||
new BlockInfo3DS {Offset = 0x01000, Length = 0x00168},
|
||||
new BlockInfo3DS {Offset = 0x01200, Length = 0x01800},
|
||||
new BlockInfo3DS {Offset = 0x02A00, Length = 0x020E8},
|
||||
new BlockInfo3DS {Offset = 0x04C00, Length = 0x00930},
|
||||
new BlockInfo3DS {Offset = 0x05600, Length = 0x00004},
|
||||
new BlockInfo3DS {Offset = 0x05800, Length = 0x00130},
|
||||
new BlockInfo3DS {Offset = 0x05A00, Length = 0x00012},
|
||||
new BlockInfo3DS {Offset = 0x05C00, Length = 0x3F7A0},
|
||||
new BlockInfo3DS {Offset = 0x45400, Length = 0x00008},
|
||||
new BlockInfo3DS {Offset = 0x45600, Length = 0x00E90},
|
||||
new BlockInfo3DS {Offset = 0x46600, Length = 0x010A4},
|
||||
new BlockInfo3DS {Offset = 0x47800, Length = 0x000F0},
|
||||
new BlockInfo3DS {Offset = 0x47A00, Length = 0x06010},
|
||||
new BlockInfo3DS {Offset = 0x4DC00, Length = 0x00200},
|
||||
new BlockInfo3DS {Offset = 0x4DE00, Length = 0x00098},
|
||||
new BlockInfo3DS {Offset = 0x4E000, Length = 0x00068},
|
||||
new BlockInfo3DS {Offset = 0x4E200, Length = 0x69780},
|
||||
new BlockInfo3DS {Offset = 0xB7A00, Length = 0x000B0},
|
||||
new BlockInfo3DS {Offset = 0xB7C00, Length = 0x00940},
|
||||
new BlockInfo7b(boGG, 00, 0x00000, 0x00D90),
|
||||
new BlockInfo7b(boGG, 01, 0x00E00, 0x00200),
|
||||
new BlockInfo7b(boGG, 02, 0x01000, 0x00168),
|
||||
new BlockInfo7b(boGG, 03, 0x01200, 0x01800),
|
||||
new BlockInfo7b(boGG, 04, 0x02A00, 0x020E8),
|
||||
new BlockInfo7b(boGG, 05, 0x04C00, 0x00930),
|
||||
new BlockInfo7b(boGG, 06, 0x05600, 0x00004),
|
||||
new BlockInfo7b(boGG, 07, 0x05800, 0x00130),
|
||||
new BlockInfo7b(boGG, 08, 0x05A00, 0x00012),
|
||||
new BlockInfo7b(boGG, 09, 0x05C00, 0x3F7A0),
|
||||
new BlockInfo7b(boGG, 10, 0x45400, 0x00008),
|
||||
new BlockInfo7b(boGG, 11, 0x45600, 0x00E90),
|
||||
new BlockInfo7b(boGG, 12, 0x46600, 0x010A4),
|
||||
new BlockInfo7b(boGG, 13, 0x47800, 0x000F0),
|
||||
new BlockInfo7b(boGG, 14, 0x47A00, 0x06010),
|
||||
new BlockInfo7b(boGG, 15, 0x4DC00, 0x00200),
|
||||
new BlockInfo7b(boGG, 16, 0x4DE00, 0x00098),
|
||||
new BlockInfo7b(boGG, 17, 0x4E000, 0x00068),
|
||||
new BlockInfo7b(boGG, 18, 0x4E200, 0x69780),
|
||||
new BlockInfo7b(boGG, 19, 0xB7A00, 0x000B0),
|
||||
new BlockInfo7b(boGG, 20, 0xB7C00, 0x00940),
|
||||
};
|
||||
|
||||
private bool CanReadChecksums()
|
||||
{
|
||||
if (Blocks.Length <= 3)
|
||||
{ Debug.WriteLine($"Not enough blocks ({Blocks.Length}), aborting {nameof(CanReadChecksums)}"); return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void SetChecksums()
|
||||
{
|
||||
if (!CanReadChecksums())
|
||||
return;
|
||||
Blocks.SetChecksums(Data);
|
||||
}
|
||||
|
||||
public bool FixPreWrite() => Storage.CompressStorage();
|
||||
|
||||
protected override void SetPKM(PKM pkm)
|
||||
|
@ -202,18 +179,6 @@ namespace PKHeX.Core
|
|||
return StringConverter.SetString7b(value, maxLength, Language, PadToSize, PadWith);
|
||||
}
|
||||
|
||||
public ulong TimeStampCurrent
|
||||
{
|
||||
get => BitConverter.ToUInt64(Data, BlockInfoOffset - 0x14);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, BlockInfoOffset - 0x14);
|
||||
}
|
||||
|
||||
public ulong TimeStampPrevious
|
||||
{
|
||||
get => BitConverter.ToUInt64(Data, BlockInfoOffset - 0xC);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, BlockInfoOffset - 0xC);
|
||||
}
|
||||
|
||||
public override GameVersion Version
|
||||
{
|
||||
get
|
||||
|
|
40
PKHeX.Core/Saves/SAV_BEEF.cs
Normal file
40
PKHeX.Core/Saves/SAV_BEEF.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public abstract class SAV_BEEF : SaveFile, ISecureValueStorage
|
||||
{
|
||||
protected SAV_BEEF(byte[] data, BlockInfo[] blocks, int biOffset) : base(data)
|
||||
{
|
||||
Blocks = blocks;
|
||||
BlockInfoOffset = biOffset;
|
||||
}
|
||||
|
||||
protected SAV_BEEF(int size, BlockInfo[] blocks, int biOffset) : base(size)
|
||||
{
|
||||
Blocks = blocks;
|
||||
BlockInfoOffset = biOffset;
|
||||
}
|
||||
|
||||
protected override void SetChecksums() => Blocks.SetChecksums(Data);
|
||||
public override bool ChecksumsValid => Blocks.GetChecksumsValid(Data);
|
||||
public override string ChecksumInfo => Blocks.GetChecksumInfo(Data);
|
||||
public override string MiscSaveInfo() => string.Join(Environment.NewLine, Blocks.Select(b => b.Summary));
|
||||
|
||||
protected readonly int BlockInfoOffset;
|
||||
protected readonly BlockInfo[] Blocks;
|
||||
|
||||
public ulong TimeStampCurrent
|
||||
{
|
||||
get => BitConverter.ToUInt64(Data, BlockInfoOffset);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, BlockInfoOffset);
|
||||
}
|
||||
|
||||
public ulong TimeStampPrevious
|
||||
{
|
||||
get => BitConverter.ToUInt64(Data, BlockInfoOffset);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, BlockInfoOffset);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,6 +47,20 @@ namespace PKHeX.Core
|
|||
public virtual int MaxIV => 31;
|
||||
public ushort[] HeldItems { get; protected set; }
|
||||
|
||||
protected SaveFile(byte[] data)
|
||||
{
|
||||
Data = data;
|
||||
BAK = (byte[])Data.Clone();
|
||||
Exportable = true;
|
||||
}
|
||||
|
||||
protected SaveFile(int size)
|
||||
{
|
||||
Data = new byte[size];
|
||||
BAK = Data;
|
||||
Exportable = false;
|
||||
}
|
||||
|
||||
// General SAV Properties
|
||||
public byte[] Write(ExportFlags flags = ExportFlags.None)
|
||||
{
|
||||
|
@ -105,13 +119,11 @@ namespace PKHeX.Core
|
|||
public bool HasHoF => HoF > -1;
|
||||
public bool HasSecretBase => SecretBase > -1;
|
||||
public bool HasPSS => PSS > -1;
|
||||
public bool HasOPower => OPower > -1;
|
||||
public bool HasJPEG => JPEGData.Length > 0;
|
||||
public bool HasBox => Box > -1;
|
||||
public virtual bool HasParty => Party > -1;
|
||||
public bool HasBattleBox => BattleBox > -1;
|
||||
public bool HasFused => Fused > -1;
|
||||
public bool HasGTS => GTS > -1;
|
||||
public bool HasDaycare => Daycare > -1;
|
||||
public virtual bool HasPokeDex => PokeDex > -1;
|
||||
public virtual bool HasBoxWallpapers => GetBoxWallpaperOffset(0) > -1;
|
||||
|
@ -150,7 +162,6 @@ namespace PKHeX.Core
|
|||
public int SecretBase { get; protected set; } = int.MinValue;
|
||||
public int PSS { get; protected set; } = int.MinValue;
|
||||
public int BerryField { get; protected set; } = int.MinValue;
|
||||
public int OPower { get; protected set; } = int.MinValue;
|
||||
public int HoF { get; protected set; } = int.MinValue;
|
||||
|
||||
// SAV Properties
|
||||
|
|
|
@ -7,19 +7,15 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public class BulkStorage : SaveFile
|
||||
{
|
||||
protected BulkStorage(byte[] data, Type t, int start, int slotsPerBox = 30)
|
||||
protected BulkStorage(byte[] data, Type t, int start, int slotsPerBox = 30) : base(data)
|
||||
{
|
||||
Box = start;
|
||||
Data = data;
|
||||
SlotsPerBox = slotsPerBox;
|
||||
|
||||
blank = PKMConverter.GetBlank(t);
|
||||
var slots = (Data.Length - Box) / blank.SIZE_STORED;
|
||||
BoxCount = slots / SlotsPerBox;
|
||||
|
||||
Exportable = !IsRangeEmpty(0, Data.Length);
|
||||
BAK = (byte[])Data.Clone();
|
||||
|
||||
GetIsPKMPresent = PKX.GetFuncIsPKMPresent(blank);
|
||||
}
|
||||
|
||||
|
|
15
PKHeX.Core/Saves/Substructures/Gen5/BattleSubway5.cs
Normal file
15
PKHeX.Core/Saves/Substructures/Gen5/BattleSubway5.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class BattleSubway5 : SaveBlock
|
||||
{
|
||||
public BattleSubway5(SAV5 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int BP
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset);
|
||||
}
|
||||
}
|
||||
}
|
46
PKHeX.Core/Saves/Substructures/Gen5/BoxLayout5.cs
Normal file
46
PKHeX.Core/Saves/Substructures/Gen5/BoxLayout5.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxLayout5 : SaveBlock
|
||||
{
|
||||
public BoxLayout5(SAV5 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int CurrentBox { get => Data[Offset]; set => Data[Offset] = (byte)value; }
|
||||
public int GetBoxNameOffset(int box) => Offset + (0x28 * box) + 4;
|
||||
public int GetBoxWallpaperOffset(int box) => Offset + 0x3C4 + box;
|
||||
|
||||
public int GetBoxWallpaper(int box)
|
||||
{
|
||||
if ((uint)box > SAV.BoxCount)
|
||||
return 0;
|
||||
return Data[GetBoxWallpaperOffset(box)];
|
||||
}
|
||||
|
||||
public void SetBoxWallpaper(int box, int value)
|
||||
{
|
||||
if ((uint)box > SAV.BoxCount)
|
||||
return;
|
||||
Data[GetBoxWallpaperOffset(box)] = (byte)value;
|
||||
}
|
||||
|
||||
public string GetBoxName(int box)
|
||||
{
|
||||
if (box >= SAV.BoxCount)
|
||||
return string.Empty;
|
||||
return SAV.GetString(GetBoxNameOffset(box), 0x14);
|
||||
}
|
||||
|
||||
public void SetBoxName(int box, string value)
|
||||
{
|
||||
if (value.Length > 0x26 / 2)
|
||||
return;
|
||||
var data = SAV.SetString(value + '\uFFFF', 0x14, 0x14, 0);
|
||||
SAV.SetData(data, GetBoxNameOffset(box));
|
||||
}
|
||||
|
||||
public string this[int i]
|
||||
{
|
||||
get => GetBoxName(i);
|
||||
set => SetBoxName(i, value);
|
||||
}
|
||||
}
|
||||
}
|
39
PKHeX.Core/Saves/Substructures/Gen5/Daycare5.cs
Normal file
39
PKHeX.Core/Saves/Substructures/Gen5/Daycare5.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class Daycare5 : SaveBlock
|
||||
{
|
||||
private const int SlotSize = 4 + PKX.SIZE_5STORED + 4; // occupied u32 flag, pk5, exp
|
||||
public const int DaycareSeedSize = 16; // 8 bytes, b2w2 only
|
||||
|
||||
public Daycare5(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public ulong? GetSeed()
|
||||
{
|
||||
if (SAV.Version != GameVersion.B2W2)
|
||||
return null;
|
||||
return BitConverter.ToUInt64(Data, Offset + 0x1CC);
|
||||
}
|
||||
|
||||
public void SetSeed(string value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
var data = Util.GetBytesFromHexString(value);
|
||||
SAV.SetData(data, Offset + 0x1CC);
|
||||
}
|
||||
|
||||
|
||||
private int SlotOffset(int slot) => Offset + (SlotSize * slot);
|
||||
private int DaycareEXPOffset(int slot) => SlotOffset(slot) + 0xE0;
|
||||
|
||||
public bool? IsOccupied(int slot) => BitConverter.ToUInt32(Data, SlotOffset(slot)) == 1;
|
||||
public void SetOccupied(int slot, bool occupied) => SAV.SetData(BitConverter.GetBytes((uint)(occupied ? 1 : 0)), SlotOffset(slot));
|
||||
|
||||
public int GetOffset(int slot) => SlotOffset(slot) + 4;
|
||||
|
||||
public uint? GetEXP(int slot) => BitConverter.ToUInt32(Data, DaycareEXPOffset(slot));
|
||||
public void SetEXP(int slot, uint EXP) => SAV.SetData(BitConverter.GetBytes(EXP), SlotOffset(slot) + 0xE0);
|
||||
}
|
||||
}
|
21
PKHeX.Core/Saves/Substructures/Gen5/Misc5.cs
Normal file
21
PKHeX.Core/Saves/Substructures/Gen5/Misc5.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class Misc5 : SaveBlock
|
||||
{
|
||||
public Misc5(SAV5 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public uint Money
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset);
|
||||
}
|
||||
|
||||
public int Badges
|
||||
{
|
||||
get => Data[Offset + 0x4];
|
||||
set => Data[Offset + 0x4] = (byte)value;
|
||||
}
|
||||
}
|
||||
}
|
37
PKHeX.Core/Saves/Substructures/Gen5/MyItem5B2W2.cs
Normal file
37
PKHeX.Core/Saves/Substructures/Gen5/MyItem5B2W2.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyItem5B2W2 : MyItem
|
||||
{
|
||||
// offsets/pouch sizes are the same for both BW and B2W2, but Key Item permissions are different
|
||||
private const int HeldItem = 0x000; // 0
|
||||
private const int KeyItem = 0x4D8; // 1
|
||||
private const int TMHM = 0x624; // 2
|
||||
private const int Medicine = 0x7D8; // 3
|
||||
private const int Berry = 0x898; // 4
|
||||
|
||||
private static readonly ushort[] LegalItems = Legal.Pouch_Items_BW;
|
||||
private static readonly ushort[] LegalKeyItems = Legal.Pouch_Key_B2W2;
|
||||
private static readonly ushort[] LegalTMHMs = Legal.Pouch_TMHM_BW;
|
||||
private static readonly ushort[] LegalMedicine = Legal.Pouch_Medicine_BW;
|
||||
private static readonly ushort[] LegalBerries = Legal.Pouch_Berries_BW;
|
||||
|
||||
public MyItem5B2W2(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch4(InventoryType.Items, LegalItems, 999, Offset + HeldItem),
|
||||
new InventoryPouch4(InventoryType.KeyItems, LegalKeyItems, 1, Offset + KeyItem),
|
||||
new InventoryPouch4(InventoryType.TMHMs, LegalTMHMs, 1, Offset + TMHM),
|
||||
new InventoryPouch4(InventoryType.Medicine, LegalMedicine, 999, Offset + Medicine),
|
||||
new InventoryPouch4(InventoryType.Berries, LegalBerries, 999, Offset + Berry)
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
}
|
||||
}
|
37
PKHeX.Core/Saves/Substructures/Gen5/MyItem5BW.cs
Normal file
37
PKHeX.Core/Saves/Substructures/Gen5/MyItem5BW.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyItem5BW : MyItem
|
||||
{
|
||||
// offsets/pouch sizes are the same for both BW and B2W2, but Key Item permissions are different
|
||||
private const int HeldItem = 0x000; // 0
|
||||
private const int KeyItem = 0x4D8; // 1
|
||||
private const int TMHM = 0x624; // 2
|
||||
private const int Medicine = 0x7D8; // 3
|
||||
private const int Berry = 0x898; // 4
|
||||
|
||||
private static readonly ushort[] LegalItems = Legal.Pouch_Items_BW;
|
||||
private static readonly ushort[] LegalKeyItems = Legal.Pouch_Key_BW;
|
||||
private static readonly ushort[] LegalTMHMs = Legal.Pouch_TMHM_BW;
|
||||
private static readonly ushort[] LegalMedicine = Legal.Pouch_Medicine_BW;
|
||||
private static readonly ushort[] LegalBerries = Legal.Pouch_Berries_BW;
|
||||
|
||||
public MyItem5BW(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch4(InventoryType.Items, LegalItems, 999, Offset + HeldItem),
|
||||
new InventoryPouch4(InventoryType.KeyItems, LegalKeyItems, 1, Offset + KeyItem),
|
||||
new InventoryPouch4(InventoryType.TMHMs, LegalTMHMs, 1, Offset + TMHM),
|
||||
new InventoryPouch4(InventoryType.Medicine, LegalMedicine, 999, Offset + Medicine),
|
||||
new InventoryPouch4(InventoryType.Berries, LegalBerries, 999, Offset + Berry),
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
}
|
||||
}
|
76
PKHeX.Core/Saves/Substructures/Gen5/MysteryBlock5.cs
Normal file
76
PKHeX.Core/Saves/Substructures/Gen5/MysteryBlock5.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class MysteryBlock5 : SaveBlock
|
||||
{
|
||||
private const int FlagStart = 0;
|
||||
private const int MaxReceivedFlag = 2048;
|
||||
private const int MaxCardsPresent = 12;
|
||||
private const int FlagRegionSize = (MaxReceivedFlag / 8); // 0x100
|
||||
private const int CardStart = FlagStart + (MaxReceivedFlag / 8);
|
||||
|
||||
private const int DataSize = 0xA90;
|
||||
private int SeedOffset => Offset + DataSize;
|
||||
|
||||
// Everything is stored encrypted, and only decrypted on demand. Only crypt on object fetch...
|
||||
public MysteryBlock5(SAV5 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public MysteryGiftAlbum GiftAlbum
|
||||
{
|
||||
get
|
||||
{
|
||||
uint seed = BitConverter.ToUInt32(Data, SeedOffset);
|
||||
byte[] wcData = SAV.GetData(Offset + FlagStart, 0xA90); // Encrypted, Decrypt
|
||||
return GetAlbum(seed, wcData);
|
||||
}
|
||||
set
|
||||
{
|
||||
var wcData = SetAlbum(value);
|
||||
// Write Back
|
||||
wcData.CopyTo(Data, Offset + FlagStart);
|
||||
BitConverter.GetBytes(value.Seed).CopyTo(Data, SeedOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private static MysteryGiftAlbum GetAlbum(uint seed, byte[] wcData)
|
||||
{
|
||||
MysteryGiftAlbum Info = new MysteryGiftAlbum { Seed = seed };
|
||||
PKX.CryptArray(wcData, seed);
|
||||
|
||||
Info.Flags = new bool[MaxReceivedFlag];
|
||||
Info.Gifts = new MysteryGift[MaxCardsPresent];
|
||||
// 0x100 Bytes for Used Flags
|
||||
for (int i = 0; i < Info.Flags.Length; i++)
|
||||
Info.Flags[i] = (wcData[i / 8] >> i % 8 & 0x1) == 1;
|
||||
// 12 PGFs
|
||||
for (int i = 0; i < Info.Gifts.Length; i++)
|
||||
{
|
||||
var data = new byte[PGF.Size];
|
||||
Array.Copy(wcData, FlagRegionSize + (i * PGF.Size), data, 0, PGF.Size);
|
||||
Info.Gifts[i] = new PGF(data);
|
||||
}
|
||||
|
||||
return Info;
|
||||
}
|
||||
|
||||
private static byte[] SetAlbum(MysteryGiftAlbum value)
|
||||
{
|
||||
byte[] wcData = new byte[0xA90];
|
||||
|
||||
// Toss back into byte[]
|
||||
for (int i = 0; i < value.Flags.Length; i++)
|
||||
{
|
||||
if (value.Flags[i])
|
||||
wcData[i / 8] |= (byte) (1 << (i & 7));
|
||||
}
|
||||
|
||||
for (int i = 0; i < value.Gifts.Length; i++)
|
||||
value.Gifts[i].Data.CopyTo(wcData, 0x100 + (i * PGF.Size));
|
||||
|
||||
// Decrypted, Encrypt
|
||||
PKX.CryptArray(wcData, value.Seed);
|
||||
return wcData;
|
||||
}
|
||||
}
|
||||
}
|
29
PKHeX.Core/Saves/Substructures/Gen5/PWTBlock5.cs
Normal file
29
PKHeX.Core/Saves/Substructures/Gen5/PWTBlock5.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class PWTBlock5 : SaveBlock
|
||||
{
|
||||
public PWTBlock5(SAV5B2W2 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public ushort GetPWTRecord(int id) => GetPWTRecord((PWTRecordID)id);
|
||||
|
||||
public ushort GetPWTRecord(PWTRecordID id)
|
||||
{
|
||||
if (id < PWTRecordID.Normal || id > PWTRecordID.MixMaster)
|
||||
throw new ArgumentException(nameof(id));
|
||||
int ofs = Offset + 0x5C + ((int)id * 2);
|
||||
return BitConverter.ToUInt16(Data, ofs);
|
||||
}
|
||||
|
||||
public void SetPWTRecord(int id, ushort value) => SetPWTRecord((PWTRecordID)id, value);
|
||||
|
||||
public void SetPWTRecord(PWTRecordID id, ushort value)
|
||||
{
|
||||
if (id < PWTRecordID.Normal || id > PWTRecordID.MixMaster)
|
||||
throw new ArgumentException(nameof(id));
|
||||
int ofs = Offset + 0x5C + ((int)id * 2);
|
||||
SAV.SetData(BitConverter.GetBytes(value), ofs);
|
||||
}
|
||||
}
|
||||
}
|
89
PKHeX.Core/Saves/Substructures/Gen5/PlayerData5.cs
Normal file
89
PKHeX.Core/Saves/Substructures/Gen5/PlayerData5.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class PlayerData5 : SaveBlock
|
||||
{
|
||||
public PlayerData5(SAV5 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public string OT
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x4, 0x10);
|
||||
set => SAV.SetString(value, SAV.OTLength).CopyTo(Data, Offset + 0x4);
|
||||
}
|
||||
|
||||
public int TID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x14 + 0);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x14 + 0);
|
||||
}
|
||||
|
||||
public int SID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x14 + 2);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x14 + 2);
|
||||
}
|
||||
|
||||
public int Language
|
||||
{
|
||||
get => Data[Offset + 0x1E];
|
||||
set => Data[Offset + 0x1E] = (byte)value;
|
||||
}
|
||||
|
||||
public int Game
|
||||
{
|
||||
get => Data[Offset + 0x1F];
|
||||
set => Data[Offset + 0x1F] = (byte)value;
|
||||
}
|
||||
|
||||
public int Gender
|
||||
{
|
||||
get => Data[Offset + 0x21];
|
||||
set => Data[Offset + 0x21] = (byte)value;
|
||||
}
|
||||
|
||||
// 22,23 ??
|
||||
|
||||
public int PlayedHours
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x24);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x24);
|
||||
}
|
||||
|
||||
public int PlayedMinutes
|
||||
{
|
||||
get => Data[Offset + 0x24 + 2];
|
||||
set => Data[Offset + 0x24 + 2] = (byte)value;
|
||||
}
|
||||
|
||||
public int PlayedSeconds
|
||||
{
|
||||
get => Data[Offset + 0x24 + 3];
|
||||
set => Data[Offset + 0x24 + 3] = (byte)value;
|
||||
}
|
||||
|
||||
public int M
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Offset + 0x180);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x180);
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x186);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x186);
|
||||
}
|
||||
|
||||
public int Z
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x18A);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x18A);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x18E);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x18E);
|
||||
}
|
||||
}
|
||||
}
|
55
PKHeX.Core/Saves/Substructures/Gen6/BoxLayout6.cs
Normal file
55
PKHeX.Core/Saves/Substructures/Gen6/BoxLayout6.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public class BoxLayout6 : SaveBlock
|
||||
{
|
||||
private const int PCBackgrounds = 0x41E;
|
||||
private const int PCFlags = 0x43D;
|
||||
private const int LastViewedBoxOffset = 0x43F;
|
||||
|
||||
private const int strlen = SAV6.LongStringLength / 2;
|
||||
|
||||
public BoxLayout6(SAV6 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int GetBoxWallpaperOffset(int box) => Offset + PCBackgrounds + box;
|
||||
|
||||
public int GetBoxWallpaper(int box)
|
||||
{
|
||||
if ((uint)box > SAV.BoxCount)
|
||||
return 0;
|
||||
return Data[GetBoxWallpaperOffset(box)];
|
||||
}
|
||||
|
||||
public void SetBoxWallpaper(int box, int value)
|
||||
{
|
||||
if ((uint)box > SAV.BoxCount)
|
||||
return;
|
||||
Data[GetBoxWallpaperOffset(box)] = (byte)value;
|
||||
}
|
||||
|
||||
private int GetBoxNameOffset(int box) => Offset + (SAV6.LongStringLength * box);
|
||||
|
||||
public string GetBoxName(int box) => SAV.GetString(Data, GetBoxNameOffset(box), SAV6.LongStringLength);
|
||||
|
||||
public void SetBoxName(int box, string value)
|
||||
{
|
||||
var data = SAV.SetString(value, strlen, strlen, 0);
|
||||
var offset = GetBoxNameOffset(box) + (SAV6.LongStringLength * box);
|
||||
SAV.SetData(data, offset);
|
||||
}
|
||||
|
||||
public byte[] BoxFlags
|
||||
{
|
||||
get => new[] { Data[Offset + PCFlags] }; // 7 bits for wallpaper unlocks, top bit to unlock final box (delta episode)
|
||||
set
|
||||
{
|
||||
if (value.Length != 1)
|
||||
return;
|
||||
Data[Offset + PCFlags] = value[0];
|
||||
}
|
||||
}
|
||||
|
||||
public int BoxesUnlocked { get => Data[Offset + PCFlags + 1] - 1; set => Data[Offset + PCFlags + 1] = (byte)(value + 1); }
|
||||
|
||||
public int CurrentBox { get => Data[Offset + LastViewedBoxOffset]; set => Data[Offset + LastViewedBoxOffset] = (byte)value; }
|
||||
}
|
||||
}
|
17
PKHeX.Core/Saves/Substructures/Gen6/GameTime6.cs
Normal file
17
PKHeX.Core/Saves/Substructures/Gen6/GameTime6.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class GameTime6 : SaveBlock
|
||||
{
|
||||
public GameTime6(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
public int ResumeYear { get => BitConverter.ToInt32(Data, Offset + 0x4); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x4); }
|
||||
public int ResumeMonth { get => Data[Offset + 0x8]; set => Data[Offset + 0x8] = (byte)value; }
|
||||
public int ResumeDay { get => Data[Offset + 0x9]; set => Data[Offset + 0x9] = (byte)value; }
|
||||
public int ResumeHour { get => Data[Offset + 0xB]; set => Data[Offset + 0xB] = (byte)value; }
|
||||
public int ResumeMinute { get => Data[Offset + 0xC]; set => Data[Offset + 0xC] = (byte)value; }
|
||||
public int ResumeSeconds { get => Data[Offset + 0xD]; set => Data[Offset + 0xD] = (byte)value; }
|
||||
public uint SecondsToStart { get => BitConverter.ToUInt32(Data, Offset + 0x18); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); }
|
||||
public uint SecondsToFame { get => BitConverter.ToUInt32(Data, Offset + 0x20); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x20); }
|
||||
}
|
||||
}
|
|
@ -2,8 +2,15 @@ namespace PKHeX.Core
|
|||
{
|
||||
public interface IPokePuff
|
||||
{
|
||||
bool HasPuffData { get; }
|
||||
byte[] Puffs { get; set; }
|
||||
int PuffCount { get; set; }
|
||||
Puff6 PuffBlock { get; }
|
||||
}
|
||||
public interface IOPower
|
||||
{
|
||||
OPower6 OPowerBlock { get; }
|
||||
}
|
||||
|
||||
public interface ILink
|
||||
{
|
||||
byte[] LinkBlock { get; set; }
|
||||
}
|
||||
}
|
47
PKHeX.Core/Saves/Substructures/Gen6/ItemInfo6.cs
Normal file
47
PKHeX.Core/Saves/Substructures/Gen6/ItemInfo6.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class ItemInfo6 : SaveBlock
|
||||
{
|
||||
public ItemInfo6(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int[] SelectItems
|
||||
{
|
||||
// UP,RIGHT,DOWN,LEFT
|
||||
get
|
||||
{
|
||||
int[] list = new int[4];
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
list[i] = BitConverter.ToUInt16(Data, Offset + 10 + (2 * i));
|
||||
return list;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null || value.Length > 4)
|
||||
return;
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, Offset + 10 + (2 * i));
|
||||
}
|
||||
}
|
||||
|
||||
public int[] RecentItems
|
||||
{
|
||||
// Items recently interacted with (Give, Use)
|
||||
get
|
||||
{
|
||||
int[] list = new int[12];
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
list[i] = BitConverter.ToUInt16(Data, Offset + 20 + (2 * i));
|
||||
return list;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null || value.Length > 12)
|
||||
return;
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, Offset + 20 + (2 * i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
PKHeX.Core/Saves/Substructures/Gen6/MyItem6AO.cs
Normal file
30
PKHeX.Core/Saves/Substructures/Gen6/MyItem6AO.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyItem6AO : MyItem
|
||||
{
|
||||
private const int HeldItem = 0; // 0
|
||||
private const int KeyItem = 0x640; // 1
|
||||
private const int TMHM = 0x7C0; // 2
|
||||
private const int Medicine = 0x968; // 3, +2 items shift because 2 HMs added
|
||||
private const int Berry = 0xA70; // 4
|
||||
|
||||
public MyItem6AO(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch4(InventoryType.Items, Legal.Pouch_Items_AO, 999, Offset + HeldItem),
|
||||
new InventoryPouch4(InventoryType.KeyItems, Legal.Pouch_Key_AO, 1, Offset + KeyItem),
|
||||
new InventoryPouch4(InventoryType.TMHMs, Legal.Pouch_TMHM_AO, 1, Offset + TMHM),
|
||||
new InventoryPouch4(InventoryType.Medicine, Legal.Pouch_Medicine_AO, 999, Offset + Medicine),
|
||||
new InventoryPouch4(InventoryType.Berries, Legal.Pouch_Berry_XY, 999, Offset + Berry),
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
}
|
||||
}
|
29
PKHeX.Core/Saves/Substructures/Gen6/MyItem6XY.cs
Normal file
29
PKHeX.Core/Saves/Substructures/Gen6/MyItem6XY.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyItem6XY : MyItem
|
||||
{
|
||||
private const int HeldItem = 0; // 0
|
||||
private const int KeyItem = 0x640; // 1
|
||||
private const int TMHM = 0x7C0; // 2
|
||||
private const int Medicine = 0x968; // 3
|
||||
private const int Berry = 0xA68; // 4
|
||||
public MyItem6XY(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch4(InventoryType.Items, Legal.Pouch_Items_XY, 999, Offset + HeldItem),
|
||||
new InventoryPouch4(InventoryType.KeyItems, Legal.Pouch_Key_XY, 1, Offset + KeyItem),
|
||||
new InventoryPouch4(InventoryType.TMHMs, Legal.Pouch_TMHM_XY, 1, Offset + TMHM),
|
||||
new InventoryPouch4(InventoryType.Medicine, Legal.Pouch_Medicine_XY, 999, Offset + Medicine),
|
||||
new InventoryPouch4(InventoryType.Berries, Legal.Pouch_Berry_XY, 999, Offset + Berry),
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
}
|
||||
}
|
115
PKHeX.Core/Saves/Substructures/Gen6/MyStatus6.cs
Normal file
115
PKHeX.Core/Saves/Substructures/Gen6/MyStatus6.cs
Normal file
|
@ -0,0 +1,115 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class MyStatus6 : SaveBlock
|
||||
{
|
||||
public MyStatus6(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int TID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0);
|
||||
}
|
||||
|
||||
public int SID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 2);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 2);
|
||||
}
|
||||
|
||||
public int Game
|
||||
{
|
||||
get => Data[Offset + 4];
|
||||
set => Data[Offset + 4] = (byte)value;
|
||||
}
|
||||
|
||||
public int Gender
|
||||
{
|
||||
get => Data[Offset + 5];
|
||||
set => Data[Offset + 5] = (byte)value;
|
||||
}
|
||||
|
||||
public int MultiplayerSpriteID
|
||||
{
|
||||
get => Data[Offset + 7];
|
||||
set => Data[Offset + 7] = (byte)value;
|
||||
}
|
||||
|
||||
public int GameSyncIDSize => 16; // 64 bits
|
||||
|
||||
public string GameSyncID
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = Data.Skip(Offset + 8).Take(GameSyncIDSize / 2).Reverse().ToArray();
|
||||
return BitConverter.ToString(data).Replace("-", string.Empty);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
if (value.Length > GameSyncIDSize)
|
||||
return;
|
||||
Enumerable.Range(0, value.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Reverse()
|
||||
.Select(x => Convert.ToByte(value.Substring(x, 2), 16))
|
||||
.ToArray().CopyTo(Data, Offset + 8);
|
||||
}
|
||||
}
|
||||
|
||||
public int SubRegion
|
||||
{
|
||||
get => Data[Offset + 0x26];
|
||||
set => Data[Offset + 0x26] = (byte)value;
|
||||
}
|
||||
|
||||
public int Country
|
||||
{
|
||||
get => Data[Offset + 0x27];
|
||||
set => Data[Offset + 0x27] = (byte)value;
|
||||
}
|
||||
|
||||
public int ConsoleRegion
|
||||
{
|
||||
get => Data[Offset + 0x2C];
|
||||
set => Data[Offset + 0x2C] = (byte)value;
|
||||
}
|
||||
|
||||
public int Language
|
||||
{
|
||||
get => Data[Offset + 0x2D];
|
||||
set => Data[Offset + 0x2D] = (byte)value;
|
||||
}
|
||||
|
||||
public string OT
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x48, 0x1A);
|
||||
set => SAV.SetData(SAV.SetString(value, SAV.OTLength), Offset + 0x48);
|
||||
}
|
||||
|
||||
private int GetSayingOffset(int say) => Offset + 0x7C + (SAV6.LongStringLength * say);
|
||||
private string GetSaying(int say) => SAV.GetString(GetSayingOffset(say), SAV6.LongStringLength);
|
||||
private void SetSaying(int say, string value) => SAV.SetData(SAV.SetString(value, SAV6.LongStringLength / 2), GetSayingOffset(say));
|
||||
|
||||
public string Saying1 { get => GetSaying(0); set => SetSaying(0, value); }
|
||||
public string Saying2 { get => GetSaying(1); set => SetSaying(1, value); }
|
||||
public string Saying3 { get => GetSaying(2); set => SetSaying(2, value); }
|
||||
public string Saying4 { get => GetSaying(3); set => SetSaying(3, value); }
|
||||
public string Saying5 { get => GetSaying(4); set => SetSaying(4, value); }
|
||||
|
||||
public bool IsMegaEvolutionUnlocked
|
||||
{
|
||||
get => (Data[Offset + 0x14A] & 0x01) != 0;
|
||||
set => Data[Offset + 0x14A] = (byte)((Data[Offset + 0x14A] & 0xFE) | (value ? 1 : 0)); // in battle
|
||||
}
|
||||
|
||||
public bool IsMegaRayquazaUnlocked
|
||||
{
|
||||
get => (Data[Offset + 0x14A] & 0x02) != 0;
|
||||
set => Data[Offset + 0x14A] = (byte)((Data[Offset + 0x14A] & ~2) | (value ? 2 : 0)); // in battle
|
||||
}
|
||||
}
|
||||
}
|
27
PKHeX.Core/Saves/Substructures/Gen6/MyStatus6XY.cs
Normal file
27
PKHeX.Core/Saves/Substructures/Gen6/MyStatus6XY.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyStatus6XY : MyStatus6
|
||||
{
|
||||
public MyStatus6XY(SaveFile sav, int offset) : base(sav, offset) { }
|
||||
|
||||
public TrainerFashion6 Fashion
|
||||
{
|
||||
get => TrainerFashion6.GetFashion(SAV.Data, Offset + 0x30, SAV.Gender);
|
||||
set => value.Write(Data, Offset + 0x30);
|
||||
}
|
||||
|
||||
public string OT_Nick
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x62, SAV6.ShortStringLength / 2);
|
||||
set => SAV.SetData(SAV.SetString(value, SAV6.ShortStringLength / 2), Offset + 0x62);
|
||||
}
|
||||
|
||||
public short EyeColor
|
||||
{
|
||||
get => BitConverter.ToInt16(Data, Offset + 0x148);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x148);
|
||||
}
|
||||
}
|
||||
}
|
78
PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs
Normal file
78
PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class MysteryBlock6 : SaveBlock
|
||||
{
|
||||
private const int FlagStart = 0;
|
||||
private const int MaxReceivedFlag = 2048;
|
||||
private const int MaxCardsPresent = 24;
|
||||
// private const int FlagRegionSize = (MaxReceivedFlag / 8); // 0x100
|
||||
private const int CardStart = FlagStart + (MaxReceivedFlag / 8);
|
||||
|
||||
public MysteryBlock6(SAV6 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public bool[] MysteryGiftReceivedFlags
|
||||
{
|
||||
get => Util.GitBitFlagArray(Data, Offset + FlagStart, MaxReceivedFlag);
|
||||
set
|
||||
{
|
||||
if (value?.Length != MaxReceivedFlag)
|
||||
return;
|
||||
Util.SetBitFlagArray(Data, Offset + FlagStart, value);
|
||||
SAV.Edited = true;
|
||||
}
|
||||
}
|
||||
|
||||
public MysteryGift[] MysteryGiftCards
|
||||
{
|
||||
get
|
||||
{
|
||||
var cards = new MysteryGift[MaxCardsPresent];
|
||||
for (int i = 0; i < cards.Length; i++)
|
||||
cards[i] = GetGift(i);
|
||||
return cards;
|
||||
}
|
||||
set
|
||||
{
|
||||
int count = Math.Min(MaxCardsPresent, value.Length);
|
||||
for (int i = 0; i < count; i++)
|
||||
SetGift(value[i], i);
|
||||
for (int i = value.Length; i < MaxCardsPresent; i++)
|
||||
SetGift(new WC6(), i);
|
||||
}
|
||||
}
|
||||
|
||||
public MysteryGift GetGift(int index)
|
||||
{
|
||||
if ((uint)index > MaxCardsPresent)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
var offset = GetGiftOffset(index);
|
||||
var data = SAV.GetData(offset, WC6.Size);
|
||||
return new WC6(data);
|
||||
}
|
||||
|
||||
private int GetGiftOffset(int index) => Offset + CardStart + (index * WC6.Size);
|
||||
|
||||
public void SetGift(MysteryGift wc6, int index)
|
||||
{
|
||||
if ((uint)index > MaxCardsPresent)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
if (wc6.Data.Length != WC6.Size)
|
||||
throw new InvalidCastException(nameof(wc6));
|
||||
|
||||
if (wc6.CardID == 2048 && wc6.ItemID == 726) // Eon Ticket (OR/AS)
|
||||
{
|
||||
if (!(SAV is SAV6AO ao))
|
||||
return;
|
||||
// Set the special received data
|
||||
var info = ao.Sango;
|
||||
info.ReceiveEon();
|
||||
info.EnableSendEon();
|
||||
}
|
||||
|
||||
SAV.SetData(wc6.Data, GetGiftOffset(index));
|
||||
}
|
||||
}
|
||||
}
|
64
PKHeX.Core/Saves/Substructures/Gen6/PlayTime6.cs
Normal file
64
PKHeX.Core/Saves/Substructures/Gen6/PlayTime6.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class PlayTime6 : SaveBlock
|
||||
{
|
||||
public PlayTime6(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int PlayedHours
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset);
|
||||
}
|
||||
|
||||
public int PlayedMinutes
|
||||
{
|
||||
get => Data[Offset + 2];
|
||||
set => Data[Offset + 2] = (byte)value;
|
||||
}
|
||||
|
||||
public int PlayedSeconds
|
||||
{
|
||||
get => Data[Offset + 3];
|
||||
set => Data[Offset + 3] = (byte)value;
|
||||
}
|
||||
|
||||
private uint LastSaved { get => BitConverter.ToUInt32(Data, Offset + 0x4); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x4); }
|
||||
private int LastSavedYear { get => (int)(LastSaved & 0xFFF); set => LastSaved = (LastSaved & 0xFFFFF000) | (uint)value; }
|
||||
private int LastSavedMonth { get => (int)(LastSaved >> 12 & 0xF); set => LastSaved = (LastSaved & 0xFFFF0FFF) | ((uint)value & 0xF) << 12; }
|
||||
private int LastSavedDay { get => (int)(LastSaved >> 16 & 0x1F); set => LastSaved = (LastSaved & 0xFFE0FFFF) | ((uint)value & 0x1F) << 16; }
|
||||
private int LastSavedHour { get => (int)(LastSaved >> 21 & 0x1F); set => LastSaved = (LastSaved & 0xFC1FFFFF) | ((uint)value & 0x1F) << 21; }
|
||||
private int LastSavedMinute { get => (int)(LastSaved >> 26 & 0x3F); set => LastSaved = (LastSaved & 0x03FFFFFF) | ((uint)value & 0x3F) << 26; }
|
||||
public string LastSavedTime => $"{LastSavedYear:0000}{LastSavedMonth:00}{LastSavedDay:00}{LastSavedHour:00}{LastSavedMinute:00}";
|
||||
|
||||
public DateTime? LastSavedDate
|
||||
{
|
||||
get => !Util.IsDateValid(LastSavedYear, LastSavedMonth, LastSavedDay)
|
||||
? (DateTime?)null
|
||||
: new DateTime(LastSavedYear, LastSavedMonth, LastSavedDay, LastSavedHour, LastSavedMinute, 0);
|
||||
set
|
||||
{
|
||||
// Only update the properties if a value is provided.
|
||||
if (value.HasValue)
|
||||
{
|
||||
var dt = value.Value;
|
||||
LastSavedYear = dt.Year;
|
||||
LastSavedMonth = dt.Month;
|
||||
LastSavedDay = dt.Day;
|
||||
LastSavedHour = dt.Hour;
|
||||
LastSavedMinute = dt.Minute;
|
||||
}
|
||||
else // Clear the date.
|
||||
{
|
||||
// If code tries to access MetDate again, null will be returned.
|
||||
LastSavedYear = 0;
|
||||
LastSavedMonth = 0;
|
||||
LastSavedDay = 0;
|
||||
LastSavedHour = 0;
|
||||
LastSavedMinute = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
59
PKHeX.Core/Saves/Substructures/Gen6/Puff6.cs
Normal file
59
PKHeX.Core/Saves/Substructures/Gen6/Puff6.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class Puff6 : SaveBlock
|
||||
{
|
||||
private const int MaxPuffID = 26; // Supreme Winter Poké Puff
|
||||
private const int PuffSlots = 100;
|
||||
|
||||
public Puff6(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public byte[] Puffs
|
||||
{
|
||||
get => SAV.GetData(Offset, PuffSlots);
|
||||
set => SAV.SetData(value, Offset);
|
||||
}
|
||||
|
||||
public int PuffCount
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Offset + PuffSlots);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset + PuffSlots);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Array.Clear(Data, Offset, PuffSlots);
|
||||
// Set the first few default Puffs
|
||||
Data[Offset + 0] = 1;
|
||||
Data[Offset + 1] = 2;
|
||||
Data[Offset + 2] = 3;
|
||||
Data[Offset + 3] = 4;
|
||||
Data[Offset + 4] = 5;
|
||||
PuffCount = 5;
|
||||
}
|
||||
|
||||
public void MaxCheat(bool special = false)
|
||||
{
|
||||
if (special)
|
||||
{
|
||||
for (int i = 0; i < PuffSlots; i++)
|
||||
Data[Offset + i] = (byte)(21 + Util.Rand.Next(2)); // Supreme Wish or Honor
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < PuffSlots; i++)
|
||||
Data[Offset + i] = (byte)((i % MaxPuffID) + 1);
|
||||
Util.Shuffle(Data, Offset, Offset + PuffSlots);
|
||||
}
|
||||
PuffCount = PuffSlots;
|
||||
}
|
||||
|
||||
public void Sort(bool reverse = false)
|
||||
{
|
||||
Array.Sort(Data, Offset, PuffCount);
|
||||
if (reverse)
|
||||
Array.Reverse(Data, Offset, PuffCount);
|
||||
}
|
||||
}
|
||||
}
|
54
PKHeX.Core/Saves/Substructures/Gen6/Record6.cs
Normal file
54
PKHeX.Core/Saves/Substructures/Gen6/Record6.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class Record6 : SaveBlock
|
||||
{
|
||||
public const int RecordCount = 200;
|
||||
protected readonly IReadOnlyList<byte> RecordMax;
|
||||
|
||||
public Record6(SAV6 sav, int offset, IReadOnlyList<byte> maxes) : base(sav)
|
||||
{
|
||||
Offset = offset;
|
||||
RecordMax = maxes;
|
||||
}
|
||||
|
||||
public Record6(SAV7 sav, int offset, IReadOnlyList<byte> maxes) : base(sav)
|
||||
{
|
||||
Offset = offset;
|
||||
RecordMax = maxes;
|
||||
}
|
||||
|
||||
public int GetRecord(int recordID)
|
||||
{
|
||||
int ofs = Records.GetOffset(Offset, recordID);
|
||||
if (recordID < 100)
|
||||
return BitConverter.ToInt32(Data, ofs);
|
||||
if (recordID < 200)
|
||||
return BitConverter.ToInt16(Data, ofs);
|
||||
Trace.Fail(nameof(recordID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetRecord(int recordID, int value)
|
||||
{
|
||||
Debug.Assert(recordID < RecordCount);
|
||||
int ofs = GetRecordOffset(recordID);
|
||||
int max = GetRecordMax(recordID);
|
||||
if (value > max)
|
||||
value = max;
|
||||
if (recordID < 100)
|
||||
BitConverter.GetBytes(value).CopyTo(Data, ofs);
|
||||
else if (recordID < 200)
|
||||
BitConverter.GetBytes((ushort)value).CopyTo(Data, ofs);
|
||||
else
|
||||
Trace.Fail(nameof(recordID));
|
||||
}
|
||||
|
||||
public int GetRecordMax(int recordID) => Records.GetMax(recordID, RecordMax);
|
||||
public int GetRecordOffset(int recordID) => Records.GetOffset(Offset, recordID);
|
||||
public void AddRecord(int recordID, int count = 1) => SetRecord(recordID, GetRecord(recordID) + count);
|
||||
}
|
||||
}
|
32
PKHeX.Core/Saves/Substructures/Gen6/SangoInfoBlock.cs
Normal file
32
PKHeX.Core/Saves/Substructures/Gen6/SangoInfoBlock.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class SangoInfoBlock : SaveBlock
|
||||
{
|
||||
public SangoInfoBlock(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
private const uint EON_MAGIC = 0x225D73C2;
|
||||
|
||||
public uint EonTicketReceivedMagic // 0x319B8
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x63B8);
|
||||
set => SAV.SetData(BitConverter.GetBytes(value), Offset + 0x63B8);
|
||||
}
|
||||
|
||||
public string SecretBaseQRText // 0x319BC -- 17*u16
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x63BC, 0x10);
|
||||
set => SAV.SetData(SAV.SetString(value, 0x10), Offset + 0x63BC);
|
||||
}
|
||||
|
||||
public uint EonTicketSendMagic // 0x319DE
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x63DE);
|
||||
set => SAV.SetData(BitConverter.GetBytes(value), Offset + 0x63DE);
|
||||
}
|
||||
|
||||
public void ReceiveEon() => EonTicketReceivedMagic = EON_MAGIC;
|
||||
public void EnableSendEon() => EonTicketSendMagic = EON_MAGIC;
|
||||
}
|
||||
}
|
60
PKHeX.Core/Saves/Substructures/Gen6/Situation6.cs
Normal file
60
PKHeX.Core/Saves/Substructures/Gen6/Situation6.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class Situation6 : SaveBlock
|
||||
{
|
||||
public Situation6(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public int M
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x02);
|
||||
set
|
||||
{
|
||||
var val = BitConverter.GetBytes((ushort)value);
|
||||
val.CopyTo(Data, Offset + 0x02);
|
||||
val.CopyTo(Data, Offset + 0x02 + 0xF4);
|
||||
}
|
||||
}
|
||||
|
||||
public float X
|
||||
{
|
||||
get => BitConverter.ToSingle(Data, Offset + 0x10) / 18;
|
||||
set
|
||||
{
|
||||
var val = BitConverter.GetBytes(value * 18);
|
||||
val.CopyTo(Data, Offset + 0x10);
|
||||
val.CopyTo(Data, Offset + 0x10 + 0xF4);
|
||||
}
|
||||
}
|
||||
|
||||
public float Z
|
||||
{
|
||||
get => BitConverter.ToSingle(Data, Offset + 0x14);
|
||||
set
|
||||
{
|
||||
var val = BitConverter.GetBytes(value);
|
||||
val.CopyTo(Data, Offset + 0x14);
|
||||
val.CopyTo(Data, Offset + 0x14 + 0xF4);
|
||||
}
|
||||
}
|
||||
|
||||
public float Y
|
||||
{
|
||||
get => BitConverter.ToSingle(Data, Offset + 0x18) / 18;
|
||||
set
|
||||
{
|
||||
var val = BitConverter.GetBytes(value * 18);
|
||||
val.CopyTo(Data, Offset + 0x18);
|
||||
val.CopyTo(Data, Offset + 0x18 + 0xF4);
|
||||
}
|
||||
}
|
||||
|
||||
// xy only
|
||||
public int Style
|
||||
{
|
||||
get => Data[Offset + 0x14D];
|
||||
set => Data[Offset + 0x14D] = (byte)value;
|
||||
}
|
||||
}
|
||||
}
|
40
PKHeX.Core/Saves/Substructures/Gen7/BattleTree7.cs
Normal file
40
PKHeX.Core/Saves/Substructures/Gen7/BattleTree7.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class BattleTree7 : SaveBlock
|
||||
{
|
||||
public BattleTree7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int GetTreeStreak(int battletype, bool super, bool max)
|
||||
{
|
||||
if (battletype > 3)
|
||||
throw new ArgumentException(nameof(battletype));
|
||||
|
||||
var offset = GetStreakOffset(battletype, super, max);
|
||||
return BitConverter.ToUInt16(Data, Offset + offset);
|
||||
}
|
||||
|
||||
public void SetTreeStreak(int value, int battletype, bool super, bool max)
|
||||
{
|
||||
if (battletype > 3)
|
||||
throw new ArgumentException(nameof(battletype));
|
||||
|
||||
if (value > ushort.MaxValue)
|
||||
value = ushort.MaxValue;
|
||||
|
||||
var offset = GetStreakOffset(battletype, super, max);
|
||||
BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + offset);
|
||||
}
|
||||
|
||||
private static int GetStreakOffset(int battletype, bool super, bool max)
|
||||
{
|
||||
int offset = 8 * battletype;
|
||||
if (super)
|
||||
offset += 2;
|
||||
if (max)
|
||||
offset += 4;
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
}
|
118
PKHeX.Core/Saves/Substructures/Gen7/BoxLayout7.cs
Normal file
118
PKHeX.Core/Saves/Substructures/Gen7/BoxLayout7.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxLayout7 : SaveBlock
|
||||
{
|
||||
private const int BattleBoxFlags = 0x4C4;
|
||||
private const int PCBackgrounds = 0x5C0;
|
||||
private const int LastViewedBoxOffset = 0x5E3;
|
||||
private const int PCFlags = 0x5E0;
|
||||
|
||||
private const int strlen = SAV6.LongStringLength / 2;
|
||||
|
||||
private const int TeamCount = 6;
|
||||
private const int NONE_SELECTED = -1;
|
||||
public readonly int[] TeamSlots = new int[TeamCount * 6];
|
||||
|
||||
public BoxLayout7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int GetBoxWallpaperOffset(int box) => Offset + PCBackgrounds + box;
|
||||
|
||||
public int GetBoxWallpaper(int box)
|
||||
{
|
||||
if ((uint)box > SAV.BoxCount)
|
||||
return 0;
|
||||
return Data[GetBoxWallpaperOffset(box)];
|
||||
}
|
||||
|
||||
public void SetBoxWallpaper(int box, int value)
|
||||
{
|
||||
if ((uint)box > SAV.BoxCount)
|
||||
return;
|
||||
Data[GetBoxWallpaperOffset(box)] = (byte)value;
|
||||
}
|
||||
|
||||
private int GetBoxNameOffset(int box) => Offset + (SAV6.LongStringLength * box);
|
||||
|
||||
public string GetBoxName(int box)
|
||||
{
|
||||
return SAV.GetString(Data, GetBoxNameOffset(box), SAV6.LongStringLength);
|
||||
}
|
||||
|
||||
public void SetBoxName(int box, string value)
|
||||
{
|
||||
var data = SAV.SetString(value, strlen, strlen, 0);
|
||||
var offset = GetBoxNameOffset(box) + (SAV6.LongStringLength * box);
|
||||
SAV.SetData(data, offset);
|
||||
}
|
||||
|
||||
public byte[] BoxFlags
|
||||
{
|
||||
get => new[] { Data[Offset + PCFlags] }; // bits for wallpaper unlocks
|
||||
set
|
||||
{
|
||||
if (value.Length != 1)
|
||||
return;
|
||||
Data[Offset + PCFlags] = value[0];
|
||||
}
|
||||
}
|
||||
|
||||
public int BoxesUnlocked { get => Data[Offset + PCFlags + 1] - 1; set => Data[Offset + PCFlags + 1] = (byte)(value + 1); }
|
||||
|
||||
public int CurrentBox { get => Data[Offset + LastViewedBoxOffset]; set => Data[Offset + LastViewedBoxOffset] = (byte)value; }
|
||||
|
||||
public void LoadBattleTeams()
|
||||
{
|
||||
for (int i = 0; i < TeamCount * 6; i++)
|
||||
{
|
||||
short val = BitConverter.ToInt16(Data, Offset + BattleBoxFlags + (i * 2));
|
||||
if (val < 0)
|
||||
{
|
||||
TeamSlots[i] = NONE_SELECTED;
|
||||
continue;
|
||||
}
|
||||
|
||||
int box = val >> 8;
|
||||
int slot = val & 0xFF;
|
||||
int index = (SAV.BoxSlotCount * box) + slot;
|
||||
TeamSlots[i] = index & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearBattleTeams()
|
||||
{
|
||||
for (int i = 0; i < TeamSlots.Length; i++)
|
||||
TeamSlots[i] = NONE_SELECTED;
|
||||
for (int i = 0; i < TeamCount; i++)
|
||||
SetIsTeamLocked(i, false);
|
||||
}
|
||||
|
||||
public void SaveBattleTeams()
|
||||
{
|
||||
for (int i = 0; i < TeamCount * 6; i++)
|
||||
{
|
||||
int index = TeamSlots[i];
|
||||
if (index < 0)
|
||||
{
|
||||
BitConverter.GetBytes((short)index).CopyTo(Data, Offset + BattleBoxFlags + (i * 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
int box = index / SAV.BoxSlotCount;
|
||||
int slot = index % SAV.BoxSlotCount;
|
||||
int val = (box << 8) | slot;
|
||||
BitConverter.GetBytes((short)val).CopyTo(Data, Offset + BattleBoxFlags + (i * 2));
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetIsTeamLocked(int team) => Data[Offset + PCBackgrounds - TeamCount - team] == 1;
|
||||
public void SetIsTeamLocked(int team, bool value) => Data[Offset + PCBackgrounds - TeamCount - team] = (byte)(value ? 1 : 0);
|
||||
|
||||
public string this[int i]
|
||||
{
|
||||
get => GetBoxName(i);
|
||||
set => SetBoxName(i, value);
|
||||
}
|
||||
}
|
||||
}
|
86
PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7.cs
Normal file
86
PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class ConfigSave7 : SaveBlock
|
||||
{
|
||||
/* ===32 bits===
|
||||
* talkSpeed:2 0,1
|
||||
* battleAnim:1 2
|
||||
* battleStyle:1 3
|
||||
* unknown:9 4..12
|
||||
* buttonMode:2 13,14
|
||||
* boxStatus:1 15
|
||||
* everything else: unknown
|
||||
*/
|
||||
|
||||
public ConfigSave7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int ConfigValue
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Offset);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset);
|
||||
}
|
||||
|
||||
public int TalkingSpeed
|
||||
{
|
||||
get => ConfigValue & 3;
|
||||
set => ConfigValue = (ConfigValue & ~3) | (value & 3);
|
||||
}
|
||||
|
||||
public int BattleAnimation
|
||||
{
|
||||
// Effects OFF = 1, Effects ON = 0
|
||||
get => (ConfigValue >> 2) & 1;
|
||||
set => ConfigValue = (ConfigValue & ~(1 << 2)) | (value << 2);
|
||||
}
|
||||
|
||||
public int BattleStyle
|
||||
{
|
||||
// SET = 1, SWITCH = 0
|
||||
get => (ConfigValue >> 3) & 1;
|
||||
set => ConfigValue = (ConfigValue & ~(1 << 3)) | (value << 3);
|
||||
}
|
||||
|
||||
// UNKNOWN?
|
||||
|
||||
public int ButtonMode
|
||||
{
|
||||
get => (ConfigValue >> 13) & 3;
|
||||
set => ConfigValue = (ConfigValue & ~(1 << 13)) | (value << 13);
|
||||
}
|
||||
|
||||
public int BoxStatus
|
||||
{
|
||||
// MANUAL = 1, AUTOMATIC = 0
|
||||
get => (ConfigValue >> 15) & 1;
|
||||
set => ConfigValue = (ConfigValue & ~(1 << 15)) | (value << 15);
|
||||
}
|
||||
|
||||
// NOTE: BELOW COMES FROM LGPE. MAYBE THIS IS WHAT THEY USE THE FLAGS FOR?
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="LanguageID"/> for messages, stored with <see cref="LanguageID.UNUSED_6"/> skipped in the enumeration.
|
||||
/// </summary>
|
||||
public int Language
|
||||
{
|
||||
get => GetLanguageID((ConfigValue >> 4) & 0xF);
|
||||
set => ConfigValue = ((ConfigValue & ~0xF0) | SetLanguageID(value) << 4);
|
||||
}
|
||||
|
||||
private static int GetLanguageID(int i) => i >= (int)LanguageID.UNUSED_6 ? i + 1 : i; // sets langBank to LanguageID
|
||||
private static int SetLanguageID(int i) => i > (int)LanguageID.UNUSED_6 ? i - 1 : i; // sets LanguageID to langBank
|
||||
|
||||
public enum BattleAnimationSetting
|
||||
{
|
||||
EffectsON,
|
||||
EffectsOFF,
|
||||
}
|
||||
|
||||
public enum BattleStyleSetting
|
||||
{
|
||||
SET,
|
||||
SWITCH,
|
||||
}
|
||||
}
|
||||
}
|
43
PKHeX.Core/Saves/Substructures/Gen7/Daycare7.cs
Normal file
43
PKHeX.Core/Saves/Substructures/Gen7/Daycare7.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public class Daycare7 : SaveBlock
|
||||
{
|
||||
public const int DaycareSeedSize = 32; // 128 bits
|
||||
|
||||
public Daycare7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public bool GetIsOccupied(int slot)
|
||||
{
|
||||
return Data[Offset + ((PKX.SIZE_6STORED + 1) * slot)] != 0;
|
||||
}
|
||||
|
||||
public void SetOccupied(int slot, bool occupied)
|
||||
{
|
||||
Data[Offset + ((PKX.SIZE_6STORED + 1) * slot)] = (byte)(occupied ? 1 : 0);
|
||||
}
|
||||
|
||||
public int GetDaycareSlotOffset(int slot)
|
||||
{
|
||||
return Offset + 1 + (slot * (PKX.SIZE_6STORED + 1));
|
||||
}
|
||||
|
||||
public bool HasEgg
|
||||
{
|
||||
get => Data[Offset + 0x1D8] == 1;
|
||||
set => Data[Offset + 0x1D8] = (byte)(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public string RNGSeed
|
||||
{
|
||||
get => Util.GetHexStringFromBytes(Data, Offset + 0x1DC, DaycareSeedSize / 2);
|
||||
set
|
||||
{
|
||||
if (value.Length != DaycareSeedSize)
|
||||
return;
|
||||
|
||||
var data = Util.GetBytesFromHexString(value);
|
||||
SAV.SetData(data, Offset + 0x1DC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs
Normal file
35
PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class FashionBlock7 : SaveBlock
|
||||
{
|
||||
public FashionBlock7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
private const int FashionLength = 0x1A08;
|
||||
|
||||
public sealed class FashionItem
|
||||
{
|
||||
public bool IsOwned { get; set; }
|
||||
public bool IsNew { get; set; }
|
||||
}
|
||||
|
||||
public FashionItem[] Wardrobe
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = SAV.GetData(Offset, 0x5A8);
|
||||
return data.Select(b => new FashionItem { IsOwned = (b & 1) != 0, IsNew = (b & 2) != 0 }).ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 0x5A8)
|
||||
throw new ArgumentOutOfRangeException($"Unexpected size: 0x{value.Length:X}");
|
||||
SAV.SetData(value.Select(t => (byte)((t.IsOwned ? 1 : 0) | (t.IsNew ? 2 : 0))).ToArray(), Offset);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() => Array.Clear(Data, Offset, FashionLength);
|
||||
}
|
||||
}
|
14
PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs
Normal file
14
PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class FieldMenu7 : SaveBlock
|
||||
{
|
||||
public FieldMenu7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
// USUM ONLY
|
||||
public string RotomOT
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x30, 0x1A);
|
||||
set => SAV.SetString(value, SAV.OTLength).CopyTo(Data, Offset + 0x30);
|
||||
}
|
||||
}
|
||||
}
|
15
PKHeX.Core/Saves/Substructures/Gen7/FieldMoveModelSave7.cs
Normal file
15
PKHeX.Core/Saves/Substructures/Gen7/FieldMoveModelSave7.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class FieldMoveModelSave7 : SaveBlock
|
||||
{
|
||||
public FieldMoveModelSave7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); }
|
||||
public float X { get => BitConverter.ToSingle(Data, Offset + 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); }
|
||||
public float Z { get => BitConverter.ToSingle(Data, Offset + 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10); }
|
||||
public float Y { get => (int)BitConverter.ToSingle(Data, Offset + 0x18); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); }
|
||||
public float R { get => (int)BitConverter.ToSingle(Data, Offset + 0x20); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x20); }
|
||||
}
|
||||
}
|
19
PKHeX.Core/Saves/Substructures/Gen7/GameTime7.cs
Normal file
19
PKHeX.Core/Saves/Substructures/Gen7/GameTime7.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class GameTime7 : SaveBlock
|
||||
{
|
||||
public GameTime7(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
public int ResumeYear { get => BitConverter.ToInt32(Data, Offset + 0x4); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x4); }
|
||||
public int ResumeMonth { get => Data[Offset + 0x8]; set => Data[Offset + 0x8] = (byte)value; }
|
||||
public int ResumeDay { get => Data[Offset + 0x9]; set => Data[Offset + 0x9] = (byte)value; }
|
||||
public int ResumeHour { get => Data[Offset + 0xB]; set => Data[Offset + 0xB] = (byte)value; }
|
||||
public int ResumeMinute { get => Data[Offset + 0xC]; set => Data[Offset + 0xC] = (byte)value; }
|
||||
public int ResumeSeconds { get => Data[Offset + 0xD]; set => Data[Offset + 0xD] = (byte)value; }
|
||||
public uint SecondsToStart { get => BitConverter.ToUInt32(Data, Offset + 0x18); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x28); }
|
||||
public uint SecondsToFame { get => BitConverter.ToUInt32(Data, Offset + 0x20); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x30); }
|
||||
|
||||
public ulong AlolaTime { get => BitConverter.ToUInt64(Data, Offset + 0x48); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x48); }
|
||||
}
|
||||
}
|
86
PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs
Normal file
86
PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class JoinFesta7 : SaveBlock
|
||||
{
|
||||
public JoinFesta7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int FestaCoins
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Offset + 0x508);
|
||||
set
|
||||
{
|
||||
if (value > 9999999)
|
||||
value = 9999999;
|
||||
BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x508);
|
||||
|
||||
TotalFestaCoins = ((SAV7)SAV).GetRecord(038) + value; // UsedFestaCoins
|
||||
}
|
||||
}
|
||||
|
||||
private int TotalFestaCoins
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Offset + 0x50C);
|
||||
set
|
||||
{
|
||||
if (value > 9999999)
|
||||
value = 9999999;
|
||||
BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x50C);
|
||||
}
|
||||
}
|
||||
|
||||
public string FestivalPlazaName
|
||||
{
|
||||
get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, Offset + 0x510, 0x2A));
|
||||
set
|
||||
{
|
||||
const int max = 20;
|
||||
if (value.Length > max)
|
||||
value = value.Substring(0, max);
|
||||
Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, Offset + 0x510);
|
||||
}
|
||||
}
|
||||
|
||||
public ushort FestaRank { get => BitConverter.ToUInt16(Data, Offset + 0x53A); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x53A); }
|
||||
public ushort GetFestaMessage(int index) => BitConverter.ToUInt16(Data, Offset + (index * 2));
|
||||
public void SetFestaMessage(int index, ushort value) => BitConverter.GetBytes(value).CopyTo(Data, Offset + (index * 2));
|
||||
public bool GetFestaPhraseUnlocked(int index) => Data[Offset + 0x2A50 + index] != 0; //index: 0 to 105:commonPhrases, 106:Lv100!
|
||||
|
||||
public void SetFestaPhraseUnlocked(int index, bool value)
|
||||
{
|
||||
if (GetFestaPhraseUnlocked(index) != value)
|
||||
Data[Offset + 0x2A50 + index] = (byte)(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public byte GetFestPrizeReceived(int index) => Data[Offset + 0x53C + index];
|
||||
public void SetFestaPrizeReceived(int index, byte value) => Data[Offset + 0x53C + index] = value;
|
||||
private int FestaYear { get => BitConverter.ToInt32(Data, Offset + 0x2F0); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x2F0); }
|
||||
private int FestaMonth { get => BitConverter.ToInt32(Data, Offset + 0x2F4); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x2F4); }
|
||||
private int FestaDay { get => BitConverter.ToInt32(Data, Offset + 0x2F8); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x2F8); }
|
||||
private int FestaHour { get => BitConverter.ToInt32(Data, Offset + 0x300); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x300); }
|
||||
private int FestaMinute { get => BitConverter.ToInt32(Data, Offset + 0x304); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x304); }
|
||||
private int FestaSecond { get => BitConverter.ToInt32(Data, Offset + 0x308); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x308); }
|
||||
|
||||
public DateTime? FestaDate
|
||||
{
|
||||
get => FestaYear >= 0 && FestaMonth > 0 && FestaDay > 0 && FestaHour >= 0 && FestaMinute >= 0 && FestaSecond >= 0 && Util.IsDateValid(FestaYear, FestaMonth, FestaDay)
|
||||
? new DateTime(FestaYear, FestaMonth, FestaDay, FestaHour, FestaMinute, FestaSecond)
|
||||
: (DateTime?)null;
|
||||
set
|
||||
{
|
||||
if (value.HasValue)
|
||||
{
|
||||
DateTime dt = value.Value;
|
||||
FestaYear = dt.Year;
|
||||
FestaMonth = dt.Month;
|
||||
FestaDay = dt.Day;
|
||||
FestaHour = dt.Hour;
|
||||
FestaMinute = dt.Minute;
|
||||
FestaSecond = dt.Second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
PKHeX.Core/Saves/Substructures/Gen7/Misc7.cs
Normal file
73
PKHeX.Core/Saves/Substructures/Gen7/Misc7.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class Misc7 : SaveBlock
|
||||
{
|
||||
public Misc7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public uint Money
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x4);
|
||||
set
|
||||
{
|
||||
if (value > 9999999)
|
||||
value = 9999999;
|
||||
SAV.SetData(BitConverter.GetBytes(value), Offset + 0x4);
|
||||
}
|
||||
}
|
||||
|
||||
public uint Stamps
|
||||
{
|
||||
get => (BitConverter.ToUInt32(Data, Offset + 0x08) << 13) >> 17; // 15 stamps; discard top13, lowest4
|
||||
set
|
||||
{
|
||||
uint flags = BitConverter.ToUInt32(Data, Offset + 0x08) & 0xFFF8000F;
|
||||
flags |= (value & 0x7FFF) << 4;
|
||||
SAV.SetData(BitConverter.GetBytes(flags), Offset + 0x08);
|
||||
}
|
||||
}
|
||||
|
||||
public uint BP
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x11C);
|
||||
set
|
||||
{
|
||||
if (value > 9999)
|
||||
value = 9999;
|
||||
SAV.SetData(BitConverter.GetBytes(value), Offset + 0x11C);
|
||||
}
|
||||
}
|
||||
public int Vivillon
|
||||
{
|
||||
get => Data[Offset + 0x130] & 0x1F;
|
||||
set => Data[Offset + 0x130] = (byte)((Data[Offset + 0x130] & ~0x1F) | (value & 0x1F));
|
||||
}
|
||||
|
||||
public uint StarterEncryptionConstant
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x148);
|
||||
set => SAV.SetData(BitConverter.GetBytes(value), Offset + 0x148);
|
||||
}
|
||||
|
||||
public int DaysFromRefreshed
|
||||
{
|
||||
get => Data[Offset + 0x123];
|
||||
set => Data[Offset + 0x123] = (byte)value;
|
||||
}
|
||||
|
||||
public int GetSurfScore(int recordID)
|
||||
{
|
||||
if (recordID < 0 || recordID > 4)
|
||||
recordID = 0;
|
||||
return BitConverter.ToInt32(Data, Offset + 0x138 + (4 * recordID));
|
||||
}
|
||||
|
||||
public void SetSurfScore(int recordID, int score)
|
||||
{
|
||||
if (recordID < 0 || recordID > 4)
|
||||
recordID = 0;
|
||||
SAV.SetData(BitConverter.GetBytes(score), Offset + 0x138 + (4 * recordID));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,11 +4,8 @@ namespace PKHeX.Core
|
|||
{
|
||||
public sealed class Misc7b : SaveBlock
|
||||
{
|
||||
private readonly SaveFile SAV;
|
||||
|
||||
public Misc7b(SaveFile sav) : base(sav)
|
||||
{
|
||||
SAV = sav;
|
||||
Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.Misc);
|
||||
}
|
||||
|
||||
|
|
32
PKHeX.Core/Saves/Substructures/Gen7/MyItem7SM.cs
Normal file
32
PKHeX.Core/Saves/Substructures/Gen7/MyItem7SM.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyItem7SM : MyItem
|
||||
{
|
||||
private const int HeldItem = 0; // 430 (Case 0)
|
||||
private const int KeyItem = HeldItem + (4 * 430); // 184 (Case 4)
|
||||
private const int TMHM = KeyItem + (4 * 184); // 108 (Case 2)
|
||||
private const int Medicine = TMHM + (4 * 108); // 64 (Case 1)
|
||||
private const int Berry = Medicine + (4 * 64); // 72 (Case 3)
|
||||
private const int ZCrystals = Berry + (4 * 72); // 30 (Case 5)
|
||||
|
||||
public MyItem7SM(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch7(InventoryType.Medicine, Legal.Pouch_Medicine_SM, 999, Offset + Medicine),
|
||||
new InventoryPouch7(InventoryType.Items, Legal.Pouch_Items_SM, 999, Offset + HeldItem),
|
||||
new InventoryPouch7(InventoryType.TMHMs, Legal.Pouch_TMHM_SM, 1, Offset + TMHM),
|
||||
new InventoryPouch7(InventoryType.Berries, Legal.Pouch_Berries_SM, 999, Offset + Berry),
|
||||
new InventoryPouch7(InventoryType.KeyItems, Legal.Pouch_Key_SM, 1, Offset + KeyItem),
|
||||
new InventoryPouch7(InventoryType.ZCrystals, Legal.Pouch_ZCrystal_SM, 1, Offset + ZCrystals),
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
}
|
||||
}
|
34
PKHeX.Core/Saves/Substructures/Gen7/MyItem7USUM.cs
Normal file
34
PKHeX.Core/Saves/Substructures/Gen7/MyItem7USUM.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MyItem7USUM : MyItem
|
||||
{
|
||||
private const int HeldItem = 0; // 427 (Case 0)
|
||||
private const int KeyItem = HeldItem + (4 * 427); // 198 (Case 4)
|
||||
private const int TMHM = KeyItem + (4 * 198); // 108 (Case 2)
|
||||
private const int Medicine = TMHM + (4 * 108); // 60 (Case 1)
|
||||
private const int Berry = Medicine + (4 * 60); // 67 (Case 3)
|
||||
private const int ZCrystals = Berry + (4 * 67); // 35 (Case 5)
|
||||
private const int BattleItems = ZCrystals + (4 * 35); // 11 (Case 6)
|
||||
|
||||
public MyItem7USUM(SaveFile SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public override InventoryPouch[] Inventory
|
||||
{
|
||||
get
|
||||
{
|
||||
InventoryPouch[] pouch =
|
||||
{
|
||||
new InventoryPouch7(InventoryType.Medicine, Legal.Pouch_Medicine_SM, 999, Medicine),
|
||||
new InventoryPouch7(InventoryType.Items, Legal.Pouch_Items_SM, 999, HeldItem),
|
||||
new InventoryPouch7(InventoryType.TMHMs, Legal.Pouch_TMHM_SM, 1, TMHM),
|
||||
new InventoryPouch7(InventoryType.Berries, Legal.Pouch_Berries_SM, 999, Berry),
|
||||
new InventoryPouch7(InventoryType.KeyItems, Legal.Pouch_Key_USUM, 1, KeyItem),
|
||||
new InventoryPouch7(InventoryType.ZCrystals, Legal.Pouch_ZCrystal_USUM, 1, ZCrystals),
|
||||
new InventoryPouch7(InventoryType.BattleItems, Legal.Pouch_Roto_USUM, 999, BattleItems),
|
||||
};
|
||||
return pouch.LoadAll(Data);
|
||||
}
|
||||
set => value.SaveAll(Data);
|
||||
}
|
||||
}
|
||||
}
|
140
PKHeX.Core/Saves/Substructures/Gen7/MyStatus7.cs
Normal file
140
PKHeX.Core/Saves/Substructures/Gen7/MyStatus7.cs
Normal file
|
@ -0,0 +1,140 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class MyStatus7 : SaveBlock
|
||||
{
|
||||
public const int GameSyncIDSize = 16; // 64 bits
|
||||
public const int NexUniqueIDSize = 32; // 128 bits
|
||||
|
||||
public MyStatus7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public int TID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0);
|
||||
}
|
||||
|
||||
public int SID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 2);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 2);
|
||||
}
|
||||
|
||||
public int Game
|
||||
{
|
||||
get => Data[Offset + 4];
|
||||
set => Data[Offset + 4] = (byte)value;
|
||||
}
|
||||
|
||||
public int Gender
|
||||
{
|
||||
get => Data[Offset + 5];
|
||||
set => Data[Offset + 5] = (byte)value;
|
||||
}
|
||||
|
||||
public string GameSyncID
|
||||
{
|
||||
get => Util.GetHexStringFromBytes(Data, Offset + 0x10, GameSyncIDSize / 2);
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
if (value.Length != GameSyncIDSize)
|
||||
return;
|
||||
|
||||
var data = Util.GetBytesFromHexString(value);
|
||||
SAV.SetData(data, Offset + 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
public string NexUniqueID
|
||||
{
|
||||
get => Util.GetHexStringFromBytes(Data, Offset + 0x18, NexUniqueIDSize / 2);
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
if (value.Length != NexUniqueIDSize)
|
||||
return;
|
||||
|
||||
var data = Util.GetBytesFromHexString(value);
|
||||
SAV.SetData(data, Offset + 0x18);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] FestaID // 12byte
|
||||
{
|
||||
get => Data.Skip(Offset + 0x28).Take(4).Concat(Data.Skip(Offset + 0x18).Take(8)).ToArray();
|
||||
set
|
||||
{
|
||||
if (value?.Length != 12)
|
||||
return;
|
||||
Array.Copy(value, 0, Data, Offset + 0x28, 4);
|
||||
Array.Copy(value, 4, Data, Offset + 0x18, 8);
|
||||
}
|
||||
}
|
||||
|
||||
public int SubRegion
|
||||
{
|
||||
get => Data[Offset + 0x2E];
|
||||
set => Data[Offset + 0x2E] = (byte)value;
|
||||
}
|
||||
|
||||
public int Country
|
||||
{
|
||||
get => Data[Offset + 0x2F];
|
||||
set => Data[Offset + 0x2F] = (byte)value;
|
||||
}
|
||||
|
||||
public int ConsoleRegion
|
||||
{
|
||||
get => Data[Offset + 0x34];
|
||||
set => Data[Offset + 0x34] = (byte)value;
|
||||
}
|
||||
|
||||
public int Language
|
||||
{
|
||||
get => Data[Offset + 0x35];
|
||||
set => Data[Offset + 0x35] = (byte)value;
|
||||
}
|
||||
|
||||
public string OT
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x38, 0x1A);
|
||||
set => SAV.SetString(value, SAV.OTLength).CopyTo(Data, Offset + 0x38);
|
||||
}
|
||||
|
||||
public int DressUpSkinColor
|
||||
{
|
||||
get => (Data[Offset + 0x54] >> 2) & 7;
|
||||
set => Data[Offset + 0x54] = (byte)((Data[Offset + 0x54] & ~(7 << 2)) | (value << 2));
|
||||
}
|
||||
|
||||
public int MultiplayerSpriteID
|
||||
{
|
||||
get => Data[Offset + 0x58];
|
||||
set => Data[Offset + 0x58] = (byte)value;
|
||||
}
|
||||
|
||||
|
||||
public bool MegaUnlocked
|
||||
{
|
||||
get => (Data[Offset + 0x78] & 0x01) != 0;
|
||||
set => Data[Offset + 0x78] = (byte)((Data[Offset + 0x78] & 0xFE) | (value ? 1 : 0)); // in battle
|
||||
}
|
||||
|
||||
public bool ZMoveUnlocked
|
||||
{
|
||||
get => (Data[Offset + 0x78] & 2) != 0;
|
||||
set => Data[Offset + 0x78] = (byte)((Data[Offset + 0x78] & ~2) | (value ? 2 : 0)); // in battle
|
||||
}
|
||||
|
||||
public int BallThrowType
|
||||
{
|
||||
get => Data[Offset + 0x7A];
|
||||
set => Data[Offset + 0x7A] = (byte)(value > 8 ? 0 : value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,8 @@ namespace PKHeX.Core
|
|||
{
|
||||
public sealed class MyStatus7b : SaveBlock
|
||||
{
|
||||
private readonly SaveFile SAV;
|
||||
|
||||
public MyStatus7b(SaveFile sav) : base(sav)
|
||||
{
|
||||
SAV = sav;
|
||||
Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.MyStatus);
|
||||
}
|
||||
|
||||
|
|
69
PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
Normal file
69
PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class MysteryBlock7 : SaveBlock
|
||||
{
|
||||
private const int FlagStart = 0;
|
||||
private const int MaxReceivedFlag = 2048;
|
||||
private const int MaxCardsPresent = 48;
|
||||
// private const int FlagRegionSize = (MaxReceivedFlag / 8); // 0x100
|
||||
private const int CardStart = FlagStart + (MaxReceivedFlag / 8);
|
||||
|
||||
public MysteryBlock7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
// Mystery Gift
|
||||
public bool[] MysteryGiftReceivedFlags
|
||||
{
|
||||
get => Util.GitBitFlagArray(Data, Offset + FlagStart, MaxReceivedFlag);
|
||||
set
|
||||
{
|
||||
if (value?.Length != MaxReceivedFlag)
|
||||
return;
|
||||
Util.SetBitFlagArray(Data, Offset + FlagStart, value);
|
||||
SAV.Edited = true;
|
||||
}
|
||||
}
|
||||
|
||||
public MysteryGift[] MysteryGiftCards
|
||||
{
|
||||
get
|
||||
{
|
||||
var cards = new MysteryGift[MaxCardsPresent];
|
||||
for (int i = 0; i < cards.Length; i++)
|
||||
cards[i] = GetGift(i);
|
||||
return cards;
|
||||
}
|
||||
set
|
||||
{
|
||||
int count = Math.Min(MaxCardsPresent, value.Length);
|
||||
for (int i = 0; i < count; i++)
|
||||
SetGift(value[i], i);
|
||||
for (int i = value.Length; i < MaxCardsPresent; i++)
|
||||
SetGift(new WC7(), i);
|
||||
}
|
||||
}
|
||||
|
||||
private MysteryGift GetGift(int index)
|
||||
{
|
||||
if ((uint)index > MaxCardsPresent)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
var offset = GetGiftOffset(index);
|
||||
var data = SAV.GetData(offset, WC6.Size);
|
||||
return new WC7(data);
|
||||
}
|
||||
|
||||
private int GetGiftOffset(int index) => Offset + CardStart + (index * WC7.Size);
|
||||
|
||||
private void SetGift(MysteryGift wc7, int index)
|
||||
{
|
||||
if ((uint)index > MaxCardsPresent)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
if (wc7.Data.Length != WC7.Size)
|
||||
throw new InvalidCastException(nameof(wc7));
|
||||
|
||||
SAV.SetData(wc7.Data, GetGiftOffset(index));
|
||||
}
|
||||
}
|
||||
}
|
58
PKHeX.Core/Saves/Substructures/Gen7/PokeFinder7.cs
Normal file
58
PKHeX.Core/Saves/Substructures/Gen7/PokeFinder7.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class PokeFinder7 : SaveBlock
|
||||
{
|
||||
public PokeFinder7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public ushort CameraVersion
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x00);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x00);
|
||||
}
|
||||
|
||||
public bool GyroFlag
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x02) == 1;
|
||||
set => BitConverter.GetBytes((ushort)(value ? 1 : 0)).CopyTo(Data, Offset + 0x02);
|
||||
}
|
||||
|
||||
public uint SnapCount
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x04);
|
||||
set
|
||||
{
|
||||
if (value > 9999999) // Top bound is unchecked, check anyway
|
||||
value = 9999999;
|
||||
BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x04);
|
||||
}
|
||||
}
|
||||
|
||||
public uint ThumbsTotalValue
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x0C);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x0C);
|
||||
}
|
||||
|
||||
public uint ThumbsHighValue
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offset + 0x10);
|
||||
set
|
||||
{
|
||||
if (value > 9_999_999)
|
||||
value = 9_999_999;
|
||||
BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10);
|
||||
|
||||
if (value > ThumbsTotalValue)
|
||||
ThumbsTotalValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort TutorialFlags
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x14);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x14);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,8 +16,6 @@ namespace PKHeX.Core
|
|||
/// </remarks>
|
||||
public sealed class PokeListHeader : SaveBlock
|
||||
{
|
||||
private readonly SaveFile SAV;
|
||||
|
||||
/// <summary>
|
||||
/// Raw representation of data, casted to ushort[].
|
||||
/// </summary>
|
||||
|
@ -30,7 +28,6 @@ namespace PKHeX.Core
|
|||
|
||||
public PokeListHeader(SaveFile sav) : base(sav)
|
||||
{
|
||||
SAV = sav;
|
||||
Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.PokeListHeader);
|
||||
PokeListInfo = LoadPointerData();
|
||||
if (!sav.Exportable)
|
||||
|
|
52
PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs
Normal file
52
PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class ResortSave7 : SaveBlock
|
||||
{
|
||||
public ResortSave7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public const int ResortCount = 93;
|
||||
public int GetResortSlotOffset(int slot) => Offset + 0x16 + (slot * PKX.SIZE_6STORED);
|
||||
|
||||
public PKM[] ResortPKM
|
||||
{
|
||||
get
|
||||
{
|
||||
PKM[] data = new PKM[ResortCount];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
var bytes = SAV.GetData(GetResortSlotOffset(i), PKX.SIZE_6STORED);
|
||||
data[i] = new PK7(bytes) { Identifier = $"Resort Slot {i}" };
|
||||
}
|
||||
return data;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value?.Length != ResortCount)
|
||||
throw new ArgumentException(nameof(ResortCount));
|
||||
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
SAV.SetStoredSlot(value[i], GetResortSlotOffset(i));
|
||||
}
|
||||
}
|
||||
|
||||
public int GetPokebeanCount(int bean_id)
|
||||
{
|
||||
if ((uint)bean_id > 14)
|
||||
throw new ArgumentException("Invalid bean id!");
|
||||
return Data[Offset + 0x564C + bean_id];
|
||||
}
|
||||
|
||||
public void SetPokebeanCount(int bean_id, int count)
|
||||
{
|
||||
if ((uint)bean_id > 14)
|
||||
throw new ArgumentException("Invalid bean id!");
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
if (count > 255)
|
||||
count = 255;
|
||||
Data[Offset + 0x564C + bean_id] = (byte)count;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
public int Offset { get; protected set; }
|
||||
protected readonly byte[] Data;
|
||||
protected SaveBlock(SaveFile SAV) => Data = SAV.Data;
|
||||
protected readonly SaveFile SAV;
|
||||
protected SaveBlock(SaveFile sav) => Data = (SAV = sav).Data;
|
||||
}
|
||||
}
|
62
PKHeX.Core/Saves/Substructures/Gen7/Situation7.cs
Normal file
62
PKHeX.Core/Saves/Substructures/Gen7/Situation7.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class Situation7 : SaveBlock
|
||||
{
|
||||
public Situation7(SAV7 sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
// "StartLocation"
|
||||
public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); }
|
||||
public float X { get => BitConverter.ToSingle(Data, Offset + 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); }
|
||||
public float Z { get => BitConverter.ToSingle(Data, Offset + 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10); }
|
||||
public float Y { get => (int)BitConverter.ToSingle(Data, Offset + 0x18); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); }
|
||||
public float R { get => (int)BitConverter.ToSingle(Data, Offset + 0x20); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x20); }
|
||||
|
||||
public void UpdateOverworldCoordinates()
|
||||
{
|
||||
var o = ((SAV7) SAV).OverworldBlock;
|
||||
o.M = M;
|
||||
o.X = X;
|
||||
o.Z = Z;
|
||||
o.Y = Y;
|
||||
o.R = R;
|
||||
}
|
||||
|
||||
public int SpecialLocation
|
||||
{
|
||||
get => Data[Offset + 0x24];
|
||||
set => Data[Offset + 0x24] = (byte)value;
|
||||
}
|
||||
|
||||
public int WarpContinueRequest
|
||||
{
|
||||
get => Data[Offset + 0x6E];
|
||||
set => Data[Offset + 0x6E] = (byte)value;
|
||||
}
|
||||
|
||||
public int StepCountEgg
|
||||
{
|
||||
get => BitConverter.ToInt32(Data, Offset + 0x70);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x70);
|
||||
}
|
||||
|
||||
public int LastZoneID
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x74);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x74);
|
||||
}
|
||||
|
||||
public int StepCountFriendship
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x76);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x76);
|
||||
}
|
||||
|
||||
public int StepCountAffection // Kawaigari
|
||||
{
|
||||
get => BitConverter.ToUInt16(Data, Offset + 0x78);
|
||||
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x78);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
int[] beans = new int[Count];
|
||||
for (int i = 0; i < beans.Length; i++)
|
||||
beans[i] = SAV.GetPokebeanCount(i);
|
||||
beans[i] = SAV.ResortSave.GetPokebeanCount(i);
|
||||
return beans;
|
||||
}
|
||||
|
||||
|
@ -56,13 +56,13 @@ namespace PKHeX.Core
|
|||
if (beans.Count != Count)
|
||||
return;
|
||||
for (int i = 0; i < beans.Count; i++)
|
||||
SAV.SetPokebeanCount(i, beans[i]);
|
||||
SAV.ResortSave.SetPokebeanCount(i, beans[i]);
|
||||
}
|
||||
|
||||
public void SetCountAll(int val)
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
SAV.SetPokebeanCount(i, val);
|
||||
SAV.ResortSave.SetPokebeanCount(i, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ using static PKHeX.Core.OPower6Type;
|
|||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class OPower6
|
||||
public class OPower6 : SaveBlock
|
||||
{
|
||||
private static readonly OPowerFlagSet[] Mapping =
|
||||
{
|
||||
|
@ -41,15 +41,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private readonly byte[] Data;
|
||||
private readonly int Offset;
|
||||
|
||||
public OPower6(byte[] data, int offset)
|
||||
{
|
||||
Offset = offset;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public OPower6(SaveFile sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
private OPowerFlagSet this[OPower6Type type] => Array.Find(Mapping, t => t.Identifier == type);
|
||||
public int GetOPowerCount(OPower6Type type) => this[type].BaseCount;
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
int start = j;
|
||||
int end = j;
|
||||
if (SAV7.SanitizeFormsToIterate(spec, out int s, out int n, j, Parent.USUM))
|
||||
if (Zukan7.SanitizeFormsToIterate(spec, out int s, out int n, j, Parent.USUM))
|
||||
{
|
||||
start = s;
|
||||
end = n;
|
||||
|
|
164
PKHeX.Core/Saves/Substructures/PokeDex/Zukan5.cs
Normal file
164
PKHeX.Core/Saves/Substructures/PokeDex/Zukan5.cs
Normal file
|
@ -0,0 +1,164 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class Zukan5 : Zukan
|
||||
{
|
||||
protected override int OFS_SEEN => OFS_CAUGHT + BitSeenSize;
|
||||
protected override int OFS_CAUGHT => 0x8;
|
||||
protected override int BitSeenSize => 0x54;
|
||||
protected override int DexLangFlagByteCount => 7;
|
||||
protected override int DexLangIDCount => 7;
|
||||
|
||||
public Zukan5(SaveFile sav, int dex, int langflag)
|
||||
{
|
||||
SAV = sav;
|
||||
PokeDex = dex;
|
||||
PokeDexLanguageFlags = langflag;
|
||||
var wrap = SAV.BW ? DexFormUtil.GetDexFormIndexBW : (Func<int, int, int>)DexFormUtil.GetDexFormIndexB2W2;
|
||||
DexFormIndexFetcher = (spec, form, _) => wrap(spec, form);
|
||||
}
|
||||
|
||||
protected override int GetDexLangFlag(int lang)
|
||||
{
|
||||
lang--;
|
||||
if (lang > 5)
|
||||
lang--; // 0-6 language vals
|
||||
if ((uint)lang > 5)
|
||||
return -1;
|
||||
return lang;
|
||||
}
|
||||
|
||||
protected override bool GetSaneFormsToIterate(int species, out int formStart, out int formEnd, int formIn)
|
||||
{
|
||||
formStart = 0;
|
||||
formEnd = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void SetSpindaDexData(PKM pkm, bool alreadySeen)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetAllDexFlagsLanguage(int bit, int lang, bool value = true)
|
||||
{
|
||||
lang = GetDexLangFlag(lang);
|
||||
if (lang < 0)
|
||||
return;
|
||||
|
||||
// Set the Language
|
||||
int lbit = (bit * DexLangIDCount) + lang;
|
||||
if (bit < 493) // shifted by 1, Gen5 species do not have international language bits
|
||||
SetFlag(PokeDexLanguageFlags, lbit, value);
|
||||
}
|
||||
|
||||
protected override void SetAllDexSeenFlags(int baseBit, int altform, int gender, bool isShiny, bool value = true)
|
||||
{
|
||||
var shiny = isShiny ? 1 : 0;
|
||||
SetDexFlags(baseBit, 0, gender, shiny);
|
||||
SetFormFlags(baseBit + 1, altform, shiny, value);
|
||||
}
|
||||
|
||||
public override void SetDex(PKM pkm)
|
||||
{
|
||||
if (pkm.Species == 0)
|
||||
return;
|
||||
if (pkm.Species > SAV.MaxSpeciesID)
|
||||
return;
|
||||
|
||||
int bit = pkm.Species - 1;
|
||||
SetCaughtFlag(bit);
|
||||
|
||||
// Set the [Species/Gender/Shiny] Seen Flag
|
||||
SetAllDexSeenFlags(bit, pkm.AltForm, pkm.Gender, pkm.IsShiny);
|
||||
SetAllDexFlagsLanguage(bit, pkm.Language);
|
||||
SetFormFlags(pkm);
|
||||
}
|
||||
|
||||
private void SetCaughtFlag(int bit) => SetFlag(OFS_CAUGHT, bit);
|
||||
|
||||
private int FormLen => SAV.B2W2 ? 0xB : 0x9;
|
||||
private int FormDex => PokeDex + 0x8 + (BitSeenSize * 9);
|
||||
|
||||
private void SetFormFlags(PKM pkm)
|
||||
{
|
||||
int species = pkm.Species;
|
||||
int form = pkm.AltForm;
|
||||
var shiny = pkm.IsShiny ? 1 : 0;
|
||||
SetFormFlags(species, form, shiny);
|
||||
}
|
||||
|
||||
private void SetFormFlags(int species, int form, int shiny, bool value = true)
|
||||
{
|
||||
int fc = SAV.Personal[species].FormeCount;
|
||||
int f = DexFormIndexFetcher(species, fc, SAV.MaxSpeciesID - 1);
|
||||
if (f < 0)
|
||||
return;
|
||||
|
||||
var bit = f + form;
|
||||
|
||||
// Set Form Seen Flag
|
||||
SetFlag(FormDex + (FormLen * shiny), bit, value);
|
||||
|
||||
// Set Displayed Flag if necessary, check all flags
|
||||
if (!value || !GetIsFormDisplayed(f, fc))
|
||||
SetFlag(FormDex + (FormLen * (2 + shiny)), bit, value);
|
||||
}
|
||||
|
||||
private bool GetIsFormDisplayed(int f, int fc)
|
||||
{
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
var bit2 = f + i;
|
||||
if (GetFlag(FormDex + (FormLen * 2), bit2)) // Nonshiny
|
||||
return true; // already set
|
||||
if (GetFlag(FormDex + (FormLen * 3), bit2)) // Shiny
|
||||
return true; // already set
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool[] GetLanguageBitflags(int species)
|
||||
{
|
||||
var result = new bool[DexLangIDCount];
|
||||
int bit = species - 1;
|
||||
for (int i = 0; i < DexLangIDCount; i++)
|
||||
{
|
||||
int lbit = (bit * DexLangIDCount) + i;
|
||||
result[i] = GetFlag(PokeDexLanguageFlags, lbit);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetLanguageBitflags(int species, bool[] value)
|
||||
{
|
||||
int bit = species - 1;
|
||||
for (int i = 0; i < DexLangIDCount; i++)
|
||||
{
|
||||
int lbit = (bit * DexLangIDCount) + i;
|
||||
SetFlag(PokeDexLanguageFlags, lbit, value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleLanguageFlagsAll(bool value)
|
||||
{
|
||||
var arr = GetBlankLanguageBits(value);
|
||||
for (int i = 1; i <= SAV.MaxSpeciesID; i++)
|
||||
SetLanguageBitflags(i, arr);
|
||||
}
|
||||
|
||||
public void ToggleLanguageFlagsSingle(int species, bool value)
|
||||
{
|
||||
var arr = GetBlankLanguageBits(value);
|
||||
SetLanguageBitflags(species, arr);
|
||||
}
|
||||
|
||||
private bool[] GetBlankLanguageBits(bool value)
|
||||
{
|
||||
var result = new bool[DexLangIDCount];
|
||||
for (int i = 0; i < DexLangIDCount; i++)
|
||||
result[i] = value;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,6 @@ namespace PKHeX.Core
|
|||
|
||||
protected override void SetSpindaDexData(PKM pkm, bool alreadySeen)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void SetAllDexFlagsLanguage(int bit, int lang, bool value = true)
|
||||
|
@ -82,13 +81,13 @@ namespace PKHeX.Core
|
|||
private void SetCaughtFlag(int bit, int origin)
|
||||
{
|
||||
// Owned quality flag
|
||||
if (SAV.ORAS)
|
||||
if (SAV is SAV6AO ao)
|
||||
{
|
||||
SetFlag(OFS_CAUGHT, bit);
|
||||
// Set DexNav count (only if not encountered previously)
|
||||
var count = ((SAV6)SAV).GetEncounterCount(bit);
|
||||
var count = ao.GetEncounterCount(bit);
|
||||
if (count == 0)
|
||||
((SAV6)SAV).SetEncounterCount(bit, 1);
|
||||
ao.SetEncounterCount(bit, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -73,6 +73,11 @@ namespace PKHeX.Core
|
|||
}
|
||||
|
||||
protected override bool GetSaneFormsToIterate(int species, out int formStart, out int formEnd, int formIn)
|
||||
{
|
||||
return SanitizeFormsToIterate(species, out formStart, out formEnd, formIn, SAV.USUM);
|
||||
}
|
||||
|
||||
public static bool SanitizeFormsToIterate(int species, out int formStart, out int formEnd, int formIn, bool USUM)
|
||||
{
|
||||
// 004AA370 in Moon
|
||||
// Simplified in terms of usage -- only overrides to give all the battle forms for a pkm
|
||||
|
@ -83,6 +88,12 @@ namespace PKHeX.Core
|
|||
formEnd = 3;
|
||||
return true;
|
||||
|
||||
case 421: // Cherrim
|
||||
case 555: // Darmanitan
|
||||
case 648: // Meloetta
|
||||
case 746: // Wishiwashi
|
||||
case 778: // Mimikyu
|
||||
// Alolans
|
||||
case 020: // Raticate
|
||||
case 105: // Marowak
|
||||
formStart = 0;
|
||||
|
@ -100,22 +111,13 @@ namespace PKHeX.Core
|
|||
case 744: // Rockruff
|
||||
break;
|
||||
|
||||
case 421: // Cherrim
|
||||
case 555: // Darmanitan
|
||||
case 648: // Meloetta
|
||||
case 746: // Wishiwashi
|
||||
case 778: // Mimikyu
|
||||
formStart = 0;
|
||||
formEnd = 1;
|
||||
return true;
|
||||
|
||||
case 774 when formIn <= 6: // Minior
|
||||
break; // don't give meteor forms except the first
|
||||
|
||||
case 718 when formIn > 1:
|
||||
break;
|
||||
default:
|
||||
int count = SAV.USUM ? DexFormUtil.GetDexFormCountUSUM(species) : DexFormUtil.GetDexFormCountSM(species);
|
||||
int count = USUM ? DexFormUtil.GetDexFormCountUSUM(species) : DexFormUtil.GetDexFormCountSM(species);
|
||||
formStart = formEnd = 0;
|
||||
return count < formIn;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public static class Records
|
||||
{
|
||||
private const byte LargeRecordCount = 100;
|
||||
private const byte SmallRecordCount = 100;
|
||||
private const byte LargeRecordCount = 100; // int32
|
||||
private const byte SmallRecordCount = 100; // int16
|
||||
private const byte Count = LargeRecordCount + SmallRecordCount;
|
||||
|
||||
/// <summary>
|
||||
|
@ -27,9 +27,9 @@ namespace PKHeX.Core
|
|||
public static int GetOffset(int baseOfs, int recordID)
|
||||
{
|
||||
if (recordID < LargeRecordCount)
|
||||
return baseOfs + (recordID * 4);
|
||||
return baseOfs + (recordID * sizeof(int));
|
||||
if (recordID < Count)
|
||||
return baseOfs + (recordID * 2) + 200; // first 100 are 4bytes, so bias the difference
|
||||
return baseOfs + (recordID * sizeof(ushort)) + (LargeRecordCount * sizeof(int)); // first 100 are 4bytes, so bias the difference
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,22 +77,23 @@ namespace PKHeX.Core
|
|||
/// <summary>Determines the type of the provided save data.</summary>
|
||||
/// <param name="data">Save data of which to determine the origins of</param>
|
||||
/// <returns>Version Identifier or Invalid if type cannot be determined.</returns>
|
||||
private static GameVersion GetSAVGeneration(byte[] data)
|
||||
private static GameVersion GetSAVType(byte[] data)
|
||||
{
|
||||
if (GetIsG1SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen1;
|
||||
if (GetIsG2SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen2;
|
||||
if (GetIsG3SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen3;
|
||||
if (GetIsG4SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen4;
|
||||
if (GetIsG5SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen5;
|
||||
if (GetIsG6SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen6;
|
||||
if (GetIsG7SAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.Gen7;
|
||||
GameVersion ver;
|
||||
if ((ver = GetIsG1SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
if ((ver = GetIsG2SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
if ((ver = GetIsG3SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
if ((ver = GetIsG4SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
if ((ver = GetIsG5SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
if ((ver = GetIsG6SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
if ((ver = GetIsG7SAV(data)) != GameVersion.Invalid)
|
||||
return ver;
|
||||
|
||||
if (GetIsBelugaSAV(data) != GameVersion.Invalid)
|
||||
return GameVersion.GG;
|
||||
|
@ -106,13 +107,13 @@ namespace PKHeX.Core
|
|||
return GameVersion.BATREV;
|
||||
|
||||
if (GetIsBank7(data)) // pokebank
|
||||
return GameVersion.USUM;
|
||||
return GameVersion.Gen7;
|
||||
if (GetIsBank4(data)) // pokestock
|
||||
return GameVersion.HGSS;
|
||||
return GameVersion.Gen4;
|
||||
if (GetIsBank3(data)) // pokestock
|
||||
return GameVersion.RS;
|
||||
return GameVersion.Gen3;
|
||||
if (GetIsRanch4(data)) // ranch
|
||||
return GameVersion.DP;
|
||||
return GameVersion.DPPt;
|
||||
|
||||
return GameVersion.Invalid;
|
||||
}
|
||||
|
@ -464,16 +465,33 @@ namespace PKHeX.Core
|
|||
|
||||
private static SaveFile GetVariantSAVInternal(byte[] data)
|
||||
{
|
||||
switch (GetSAVGeneration(data))
|
||||
switch (GetSAVType(data))
|
||||
{
|
||||
// Main Games
|
||||
case GameVersion.Gen1: return new SAV1(data);
|
||||
case GameVersion.Gen2: return new SAV2(data);
|
||||
case GameVersion.Gen3: return new SAV3(data);
|
||||
case GameVersion.Gen4: return new SAV4(data);
|
||||
case GameVersion.Gen5: return new SAV5(data);
|
||||
case GameVersion.Gen6: return new SAV6(data);
|
||||
case GameVersion.Gen7: return new SAV7(data);
|
||||
case GameVersion.RBY: return new SAV1(data);
|
||||
|
||||
case GameVersion.GS:
|
||||
case GameVersion.C: return new SAV2(data);
|
||||
|
||||
case GameVersion.RS:
|
||||
case GameVersion.E:
|
||||
case GameVersion.FRLG: return new SAV3(data);
|
||||
|
||||
case GameVersion.DP:
|
||||
case GameVersion.Pt:
|
||||
case GameVersion.HGSS: return new SAV4(data);
|
||||
|
||||
case GameVersion.BW: return new SAV5BW(data);
|
||||
case GameVersion.B2W2: return new SAV5B2W2(data);
|
||||
|
||||
case GameVersion.XY: return new SAV6XY(data);
|
||||
case GameVersion.ORAS: return new SAV6AO(data);
|
||||
case GameVersion.ORASDEMO: return new SAV6AODemo(data);
|
||||
|
||||
case GameVersion.SM:
|
||||
return new SAV7SM(data);
|
||||
case GameVersion.USUM:
|
||||
return new SAV7USUM(data);
|
||||
|
||||
// Side Games
|
||||
case GameVersion.COLO: return new SAV3Colosseum(data);
|
||||
|
@ -483,10 +501,10 @@ namespace PKHeX.Core
|
|||
case GameVersion.GG: return new SAV7b(data);
|
||||
|
||||
// Bulk Storage
|
||||
case GameVersion.RS: return new Bank3(data);
|
||||
case GameVersion.DP: return new SAV4Ranch(data);
|
||||
case GameVersion.HGSS: return new Bank4(data);
|
||||
case GameVersion.USUM: return Bank7.GetBank7(data);
|
||||
case GameVersion.Gen3: return new Bank3(data);
|
||||
case GameVersion.DPPt: return new SAV4Ranch(data);
|
||||
case GameVersion.Gen4: return new Bank4(data);
|
||||
case GameVersion.Gen7: return Bank7.GetBank7(data);
|
||||
|
||||
// No pattern matched
|
||||
default: return null;
|
||||
|
@ -559,13 +577,13 @@ namespace PKHeX.Core
|
|||
return new SAV2();
|
||||
|
||||
case GameVersion.R: case GameVersion.S: case GameVersion.E: case GameVersion.FR: case GameVersion.LG:
|
||||
return new SAV3(versionOverride: Game);
|
||||
return new SAV3(version: Game);
|
||||
case GameVersion.FRLG:
|
||||
return new SAV3(versionOverride: GameVersion.FR);
|
||||
return new SAV3(version: GameVersion.FR);
|
||||
case GameVersion.RS:
|
||||
return new SAV3(versionOverride: GameVersion.R);
|
||||
return new SAV3(version: GameVersion.R);
|
||||
case GameVersion.RSE:
|
||||
return new SAV3(versionOverride: GameVersion.E);
|
||||
return new SAV3(version: GameVersion.E);
|
||||
|
||||
case GameVersion.CXD:
|
||||
case GameVersion.COLO:
|
||||
|
@ -577,31 +595,31 @@ namespace PKHeX.Core
|
|||
|
||||
case GameVersion.D: case GameVersion.P: case GameVersion.DP:
|
||||
case GameVersion.DPPt:
|
||||
return new SAV4(new byte[SIZE_G4RAW], GameVersion.DP);
|
||||
return new SAV4(GameVersion.DP);
|
||||
case GameVersion.Pt:
|
||||
return new SAV4(new byte[SIZE_G4RAW], GameVersion.Pt);
|
||||
return new SAV4(GameVersion.Pt);
|
||||
case GameVersion.HG: case GameVersion.SS: case GameVersion.HGSS:
|
||||
return new SAV4(new byte[SIZE_G4RAW], GameVersion.HGSS);
|
||||
return new SAV4(GameVersion.HGSS);
|
||||
|
||||
case GameVersion.B: case GameVersion.W: case GameVersion.BW:
|
||||
return new SAV5(new byte[SIZE_G5RAW], GameVersion.BW);
|
||||
return new SAV5BW();
|
||||
case GameVersion.B2: case GameVersion.W2: case GameVersion.B2W2:
|
||||
return new SAV5(new byte[SIZE_G5RAW], GameVersion.B2W2);
|
||||
return new SAV5B2W2();
|
||||
|
||||
case GameVersion.X: case GameVersion.Y: case GameVersion.XY:
|
||||
return new SAV6(new byte[SIZE_G6XY]);
|
||||
return new SAV6XY();
|
||||
case GameVersion.ORASDEMO:
|
||||
return new SAV6(new byte[SIZE_G6ORASDEMO]);
|
||||
return new SAV6AODemo();
|
||||
case GameVersion.OR: case GameVersion.AS: case GameVersion.ORAS:
|
||||
return new SAV6(new byte[SIZE_G6ORAS]);
|
||||
return new SAV6AO();
|
||||
|
||||
case GameVersion.SN: case GameVersion.MN: case GameVersion.SM:
|
||||
return new SAV7(new byte[SIZE_G7SM]);
|
||||
return new SAV7SM();
|
||||
case GameVersion.US: case GameVersion.UM: case GameVersion.USUM:
|
||||
return new SAV7(new byte[SIZE_G7USUM]);
|
||||
return new SAV7USUM();
|
||||
case GameVersion.GO:
|
||||
case GameVersion.GP: case GameVersion.GE: case GameVersion.GG:
|
||||
return new SAV7b(new byte[SIZE_G7GG]);
|
||||
return new SAV7b();
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
|
|
@ -17,12 +17,20 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <param name="items">Item collection</param>
|
||||
public static void Shuffle<T>(IList<T> items)
|
||||
public static void Shuffle<T>(IList<T> items) => Shuffle(items, 0, items.Count);
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles the order of items within a collection of items.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <param name="items">Item collection</param>
|
||||
/// <param name="start">Starting position</param>
|
||||
/// <param name="end">Ending position</param>
|
||||
public static void Shuffle<T>(IList<T> items, int start, int end)
|
||||
{
|
||||
int n = items.Count;
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
int index = i + Rand.Next(n-i);
|
||||
int index = i + Rand.Next(end - i);
|
||||
T t = items[index];
|
||||
items[index] = items[i];
|
||||
items[i] = t;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace PKHeX.Core
|
||||
|
@ -90,6 +91,20 @@ namespace PKHeX.Core
|
|||
return result;
|
||||
}
|
||||
|
||||
public static byte[] GetBytesFromHexString(string seed)
|
||||
{
|
||||
return Enumerable.Range(0, seed.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(seed.Substring(x, 2), 16))
|
||||
.Reverse().ToArray();
|
||||
}
|
||||
|
||||
public static string GetHexStringFromBytes(byte[] data, int offset, int length)
|
||||
{
|
||||
data = data.Skip(offset).Take(length).Reverse().ToArray();
|
||||
return BitConverter.ToString(data).Replace("-", string.Empty);
|
||||
}
|
||||
|
||||
private static bool IsNum(char c) => c >= '0' && c <= '9';
|
||||
private static bool IsHexUpper(char c) => c >= 'A' && c <= 'F';
|
||||
private static bool IsHexLower(char c) => c >= 'a' && c <= 'f';
|
||||
|
@ -128,5 +143,30 @@ namespace PKHeX.Core
|
|||
int index = input.IndexOf(c);
|
||||
return index < 0 ? input : input.Substring(0, index);
|
||||
}
|
||||
|
||||
|
||||
public static bool[] GitBitFlagArray(byte[] data, int offset, int count)
|
||||
{
|
||||
bool[] result = new bool[count];
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = (data[offset + (i >> 3)] >> (i & 7) & 0x1) == 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SetBitFlagArray(byte[] data, int offset, bool[] value)
|
||||
{
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
if (value[i])
|
||||
data[offset + (i >> 3)] |= (byte)(1 << (i & 7));
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] SetBitFlagArray(bool[] value)
|
||||
{
|
||||
byte[] data = new byte[value.Length / 8];
|
||||
SetBitFlagArray(data, 0, value);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -582,19 +582,18 @@ namespace PKHeX.WinForms.Controls
|
|||
|
||||
private void B_OpenOPowers_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (SAV.Generation != 6)
|
||||
return;
|
||||
new SAV_OPower((SAV6)SAV).ShowDialog();
|
||||
if (SAV is IOPower op)
|
||||
new SAV_OPower(op).ShowDialog();
|
||||
}
|
||||
|
||||
private void B_OpenFriendSafari_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!SAV.XY)
|
||||
if (!(SAV is SAV6XY xy))
|
||||
return;
|
||||
|
||||
var dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgSaveGen6FriendSafari, MsgSaveGen6FriendSafariCheatDesc);
|
||||
if (dr == DialogResult.Yes)
|
||||
((SAV6)SAV).UnlockAllFriendSafariSlots();
|
||||
xy.UnlockAllFriendSafariSlots();
|
||||
}
|
||||
|
||||
private static Form GetPokeDexEditor(SaveFile sav)
|
||||
|
@ -1006,13 +1005,13 @@ namespace PKHeX.WinForms.Controls
|
|||
PAN_BattleBox.Visible = L_BattleBox.Visible = L_ReadOnlyPBB.Visible = sav.HasBattleBox;
|
||||
GB_Daycare.Visible = sav.HasDaycare;
|
||||
B_OpenSecretBase.Enabled = sav.HasSecretBase;
|
||||
B_OpenPokepuffs.Enabled = sav is IPokePuff p && p.HasPuffData;
|
||||
B_OpenPokepuffs.Enabled = sav is IPokePuff;
|
||||
B_OUTPasserby.Enabled = sav.HasPSS;
|
||||
B_OpenBoxLayout.Enabled = sav.HasNamableBoxes;
|
||||
B_OpenWondercards.Enabled = sav.HasWondercards;
|
||||
B_OpenSuperTraining.Enabled = sav.HasSuperTrain;
|
||||
B_OpenHallofFame.Enabled = sav.HasHoF;
|
||||
B_OpenOPowers.Enabled = sav.HasOPower;
|
||||
B_OpenOPowers.Enabled = sav is IOPower;
|
||||
B_OpenPokedex.Enabled = sav.HasPokeDex;
|
||||
B_OpenBerryField.Enabled = sav.HasBerryField && sav.XY;
|
||||
B_OpenFriendSafari.Enabled = sav.XY;
|
||||
|
|
|
@ -9,17 +9,17 @@ namespace PKHeX.WinForms
|
|||
public partial class SAV_Link6 : Form
|
||||
{
|
||||
private readonly SaveFile Origin;
|
||||
private readonly SAV6 SAV;
|
||||
private readonly ILink SAV;
|
||||
|
||||
public SAV_Link6(SaveFile sav)
|
||||
{
|
||||
InitializeComponent();
|
||||
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
||||
SAV = (SAV6)(Origin = sav).Clone();
|
||||
SAV = (ILink)(Origin = sav).Clone();
|
||||
foreach (var cb in TAB_Items.Controls.OfType<ComboBox>())
|
||||
{
|
||||
cb.InitializeBinding();
|
||||
cb.DataSource = new BindingSource(GameInfo.ItemDataSource.Where(item => item.Value <= SAV.MaxItemID).ToArray(), null);
|
||||
cb.DataSource = new BindingSource(GameInfo.ItemDataSource.Where(item => item.Value <= sav.MaxItemID).ToArray(), null);
|
||||
}
|
||||
byte[] data = SAV.LinkBlock;
|
||||
if (data == null)
|
||||
|
@ -44,7 +44,7 @@ namespace PKHeX.WinForms
|
|||
BitConverter.GetBytes(ccitt).CopyTo(data, data.Length - 4);
|
||||
|
||||
SAV.LinkBlock = data;
|
||||
Origin.SetData(SAV.Data, 0);
|
||||
Origin.SetData(((SaveFile)SAV).Data, 0);
|
||||
Close();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,15 +6,17 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
public partial class SAV_OPower : Form
|
||||
{
|
||||
private readonly SAV6 Origin;
|
||||
private readonly SaveFile Origin;
|
||||
private readonly SaveFile SAV;
|
||||
private readonly OPower6 Data;
|
||||
|
||||
public SAV_OPower(SAV6 sav)
|
||||
public SAV_OPower(IOPower sav)
|
||||
{
|
||||
InitializeComponent();
|
||||
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
||||
Origin = sav;
|
||||
Data = sav.OPowerData;
|
||||
Origin = (SaveFile)sav;
|
||||
SAV = Origin.Clone();
|
||||
Data = ((IOPower)SAV).OPowerBlock;
|
||||
|
||||
Current = Types[0];
|
||||
foreach (var z in Types)
|
||||
|
@ -46,7 +48,8 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
Data.MasterFlag = CHK_Master.Checked;
|
||||
SaveCurrent();
|
||||
Origin.OPowerData = Data;
|
||||
Origin.Data = SAV.Data;
|
||||
Origin.Edited = true;
|
||||
}
|
||||
|
||||
private void LoadCurrent()
|
||||
|
|
|
@ -7,13 +7,13 @@ namespace PKHeX.WinForms
|
|||
public partial class SAV_PokeBlockORAS : Form
|
||||
{
|
||||
private readonly SaveFile Origin;
|
||||
private readonly SAV6 SAV;
|
||||
private readonly SAV6AO SAV;
|
||||
|
||||
public SAV_PokeBlockORAS(SaveFile sav)
|
||||
{
|
||||
InitializeComponent();
|
||||
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
||||
SAV = (SAV6)(Origin = sav).Clone();
|
||||
SAV = (SAV6AO)(Origin = sav).Clone();
|
||||
nup_spec = new[] { NUP_Red, NUP_Blue, NUP_Pink, NUP_Green, NUP_Yellow, NUP_Rainbow, NUP_RedPlus, NUP_BluePlus, NUP_PinkPlus, NUP_GreenPlus, NUP_YellowPlus, NUP_RainbowPlus };
|
||||
Label[] lbl_spec = { L_Red, L_Blue, L_Pink, L_Green, L_Yellow, L_Rainbow, L_RedPlus, L_BluePlus, L_PinkPlus, L_GreenPlus, L_YellowPlus, L_RainbowPlus };
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PKHeX.Core;
|
||||
|
||||
|
@ -14,9 +13,9 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
InitializeComponent();
|
||||
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
||||
SAV = (SAV6)sav;
|
||||
SAV = (IPokePuff)sav;
|
||||
|
||||
var puffs = SAV.Puffs;
|
||||
var puffs = SAV.PuffBlock.Puffs;
|
||||
Setup(puffs.Length);
|
||||
LoadPuffs(puffs);
|
||||
|
||||
|
@ -87,41 +86,20 @@ namespace PKHeX.WinForms
|
|||
|
||||
private void B_All_Click(object sender, EventArgs e)
|
||||
{
|
||||
int[] plus10 = {21, 22};
|
||||
byte[] newpuffs = new byte[PuffCount];
|
||||
|
||||
if (ModifierKeys == Keys.Control)
|
||||
{
|
||||
for (int i = 0; i < PuffCount; i++)
|
||||
newpuffs[i] = (byte)plus10[Util.Rand.Next(2)];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < PuffCount; i++)
|
||||
newpuffs[i] = (byte)((i % (pfa.Length - 1)) + 1);
|
||||
Util.Shuffle(newpuffs);
|
||||
}
|
||||
|
||||
LoadPuffs(newpuffs);
|
||||
SAV.PuffBlock.MaxCheat(ModifierKeys == Keys.Control);
|
||||
LoadPuffs(SAV.PuffBlock.Puffs);
|
||||
}
|
||||
|
||||
private void B_None_Click(object sender, EventArgs e)
|
||||
{
|
||||
byte[] newpuffs = new byte[PuffCount];
|
||||
newpuffs[0] = 1;
|
||||
newpuffs[1] = 2;
|
||||
newpuffs[2] = 3;
|
||||
newpuffs[3] = 4;
|
||||
newpuffs[4] = 5;
|
||||
LoadPuffs(newpuffs);
|
||||
SAV.PuffBlock.Reset();
|
||||
LoadPuffs(SAV.PuffBlock.Puffs);
|
||||
}
|
||||
|
||||
private void B_Sort_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool reverse = ModifierKeys == Keys.Control;
|
||||
var puffs = GetPuffs().GroupBy(z => z != 0);
|
||||
var result = puffs.SelectMany(z => reverse ? z.OrderByDescending(x => x) : z.OrderBy(x => x)).ToArray();
|
||||
LoadPuffs(result);
|
||||
SAV.PuffBlock.Sort(ModifierKeys == Keys.Control);
|
||||
LoadPuffs(SAV.PuffBlock.Puffs);
|
||||
}
|
||||
|
||||
private byte[] GetPuffs()
|
||||
|
@ -139,8 +117,8 @@ namespace PKHeX.WinForms
|
|||
private void B_Save_Click(object sender, EventArgs e)
|
||||
{
|
||||
var puffs = GetPuffs();
|
||||
SAV.Puffs = puffs;
|
||||
SAV.PuffCount = puffs.Length;
|
||||
SAV.PuffBlock.Puffs = puffs;
|
||||
SAV.PuffBlock.PuffCount = puffs.Length;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@ namespace PKHeX.WinForms
|
|||
CB_Ability.InitializeBinding();
|
||||
|
||||
LB_Favorite.SelectedIndex = 0;
|
||||
// MT_Flags.Text = BitConverter.ToUInt16(sav, 0x24800 + 0x140).ToString(); PSS Stat transmitted
|
||||
MT_Flags.Text = BitConverter.ToUInt32(SAV.Data, SAV.SecretBase + 0x62C).ToString(); // read counter
|
||||
MT_Flags.Text = SAV.Records.GetRecord(080).ToString(); // read counter; also present in the Secret Base data block
|
||||
B_SAV2FAV(null, EventArgs.Empty);
|
||||
}
|
||||
|
||||
|
@ -215,7 +214,7 @@ namespace PKHeX.WinForms
|
|||
private void B_Save_Click(object sender, EventArgs e)
|
||||
{
|
||||
uint flags = Util.ToUInt32(MT_Flags.Text);
|
||||
Array.Copy(BitConverter.GetBytes(flags), 0, SAV.Data, SAV.Record + 0x140, 4); // write pss
|
||||
SAV.Records.SetRecord(080, (int)flags);
|
||||
Array.Copy(BitConverter.GetBytes(flags), 0, SAV.Data, SAV.SecretBase + 0x62C, 4); // write counter
|
||||
Origin.SetData(SAV.Data, 0);
|
||||
Close();
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace PKHeX.WinForms
|
|||
this.CHK_MegaUnlocked = new System.Windows.Forms.CheckBox();
|
||||
this.Tab_Maison = new System.Windows.Forms.TabPage();
|
||||
this.Tab_Appearance = new System.Windows.Forms.TabPage();
|
||||
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
|
||||
this.PG_CurrentAppearance = new System.Windows.Forms.PropertyGrid();
|
||||
this.L_TRNick = new System.Windows.Forms.Label();
|
||||
this.TB_TRNick = new System.Windows.Forms.TextBox();
|
||||
this.CHK_MegaRayquazaUnlocked = new System.Windows.Forms.CheckBox();
|
||||
|
@ -1620,7 +1620,7 @@ namespace PKHeX.WinForms
|
|||
//
|
||||
// Tab_Appearance
|
||||
//
|
||||
this.Tab_Appearance.Controls.Add(this.propertyGrid1);
|
||||
this.Tab_Appearance.Controls.Add(this.PG_CurrentAppearance);
|
||||
this.Tab_Appearance.Controls.Add(this.L_TRNick);
|
||||
this.Tab_Appearance.Controls.Add(this.TB_TRNick);
|
||||
this.Tab_Appearance.Controls.Add(this.B_GiveAccessories);
|
||||
|
@ -1633,15 +1633,15 @@ namespace PKHeX.WinForms
|
|||
//
|
||||
// propertyGrid1
|
||||
//
|
||||
this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
this.PG_CurrentAppearance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.propertyGrid1.HelpVisible = false;
|
||||
this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
|
||||
this.propertyGrid1.Name = "propertyGrid1";
|
||||
this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.Alphabetical;
|
||||
this.propertyGrid1.Size = new System.Drawing.Size(281, 247);
|
||||
this.propertyGrid1.TabIndex = 75;
|
||||
this.propertyGrid1.ToolbarVisible = false;
|
||||
this.PG_CurrentAppearance.HelpVisible = false;
|
||||
this.PG_CurrentAppearance.Location = new System.Drawing.Point(3, 3);
|
||||
this.PG_CurrentAppearance.Name = "PG_CurrentAppearance";
|
||||
this.PG_CurrentAppearance.PropertySort = System.Windows.Forms.PropertySort.Alphabetical;
|
||||
this.PG_CurrentAppearance.Size = new System.Drawing.Size(281, 247);
|
||||
this.PG_CurrentAppearance.TabIndex = 75;
|
||||
this.PG_CurrentAppearance.ToolbarVisible = false;
|
||||
//
|
||||
// L_TRNick
|
||||
//
|
||||
|
@ -1860,7 +1860,7 @@ namespace PKHeX.WinForms
|
|||
private System.Windows.Forms.TextBox TB_TRNick;
|
||||
private System.Windows.Forms.CheckBox CHK_MegaUnlocked;
|
||||
private Subforms.Save_Editors.TrainerStat TrainerStats;
|
||||
private System.Windows.Forms.PropertyGrid propertyGrid1;
|
||||
private System.Windows.Forms.PropertyGrid PG_CurrentAppearance;
|
||||
private System.Windows.Forms.CheckBox CHK_MegaRayquazaUnlocked;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,8 +63,9 @@ namespace PKHeX.WinForms
|
|||
GetBadges();
|
||||
editing = false;
|
||||
|
||||
CHK_MegaUnlocked.Checked = SAV.IsMegaEvolutionUnlocked;
|
||||
CHK_MegaRayquazaUnlocked.Checked = SAV.IsMegaRayquazaUnlocked;
|
||||
var status = SAV.Status;
|
||||
CHK_MegaUnlocked.Checked = status.IsMegaEvolutionUnlocked;
|
||||
CHK_MegaRayquazaUnlocked.Checked = status.IsMegaRayquazaUnlocked;
|
||||
}
|
||||
|
||||
private readonly bool editing = true;
|
||||
|
@ -146,11 +147,12 @@ namespace PKHeX.WinForms
|
|||
MT_SID.Text = SAV.SID.ToString("00000");
|
||||
MT_Money.Text = SAV.Money.ToString();
|
||||
|
||||
TB_Saying1.Text = SAV.Saying1;
|
||||
TB_Saying2.Text = SAV.Saying2;
|
||||
TB_Saying3.Text = SAV.Saying3;
|
||||
TB_Saying4.Text = SAV.Saying4;
|
||||
TB_Saying5.Text = SAV.Saying5;
|
||||
var status = SAV.Status;
|
||||
TB_Saying1.Text = status.Saying1;
|
||||
TB_Saying2.Text = status.Saying2;
|
||||
TB_Saying3.Text = status.Saying3;
|
||||
TB_Saying4.Text = status.Saying4;
|
||||
TB_Saying5.Text = status.Saying5;
|
||||
|
||||
CB_Country.SelectedValue = SAV.Country;
|
||||
CB_Region.SelectedValue = SAV.SubRegion;
|
||||
|
@ -164,9 +166,10 @@ namespace PKHeX.WinForms
|
|||
MaisonRecords[i].Text = SAV.GetMaisonStat(i).ToString();
|
||||
}
|
||||
|
||||
NUD_M.Value = SAV.M;
|
||||
var sit = SAV.Situation;
|
||||
NUD_M.Value = sit.M;
|
||||
// Sanity Check Map Coordinates
|
||||
if (!GB_Map.Enabled || SAV.X%0.5 != 0 || SAV.Z%0.5 != 0 || SAV.Y%0.5 != 0)
|
||||
if (!GB_Map.Enabled || sit.X%0.5 != 0 || sit.Z%0.5 != 0 || sit.Y%0.5 != 0)
|
||||
{
|
||||
GB_Map.Enabled = false;
|
||||
}
|
||||
|
@ -174,9 +177,9 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
try
|
||||
{
|
||||
NUD_X.Value = (decimal)SAV.X;
|
||||
NUD_Z.Value = (decimal)SAV.Z;
|
||||
NUD_Y.Value = (decimal)SAV.Y;
|
||||
NUD_X.Value = (decimal)sit.X;
|
||||
NUD_Z.Value = (decimal)sit.Z;
|
||||
NUD_Y.Value = (decimal)sit.Y;
|
||||
}
|
||||
catch { GB_Map.Enabled = false; }
|
||||
}
|
||||
|
@ -185,7 +188,7 @@ namespace PKHeX.WinForms
|
|||
TB_BP.Text = SAV.BP.ToString();
|
||||
TB_PM.Text = SAV.GetRecord(63).ToString();
|
||||
|
||||
TB_Style.Text = SAV.Style.ToString();
|
||||
TB_Style.Text = sit.Style.ToString();
|
||||
|
||||
// Load Play Time
|
||||
MT_Hours.Text = SAV.PlayedHours.ToString();
|
||||
|
@ -196,19 +199,18 @@ namespace PKHeX.WinForms
|
|||
CB_MultiplayerSprite.SelectedValue = SAV.MultiplayerSpriteID;
|
||||
PB_Sprite.Image = SAV.Sprite();
|
||||
|
||||
if (SAV.XY)
|
||||
if (SAV is SAV6XY xy)
|
||||
{
|
||||
// Load Clothing Data
|
||||
propertyGrid1.SelectedObject = TrainerFashion6.GetFashion(SAV.Data, SAV.TrainerCard + 0x30, SAV.Gender);
|
||||
|
||||
TB_TRNick.Text = SAV.OT_Nick;
|
||||
var xystat = ((MyStatus6XY) xy.Status);
|
||||
PG_CurrentAppearance.SelectedObject = xystat.Fashion;
|
||||
TB_TRNick.Text = xystat.OT_Nick;
|
||||
}
|
||||
|
||||
CB_Vivillon.SelectedIndex = SAV.Vivillon;
|
||||
if (SAV.LastSavedDate.HasValue)
|
||||
if (SAV.Played.LastSavedDate.HasValue)
|
||||
{
|
||||
CAL_LastSavedDate.Value = SAV.LastSavedDate.Value;
|
||||
CAL_LastSavedTime.Value = SAV.LastSavedDate.Value;
|
||||
CAL_LastSavedDate.Value = SAV.Played.LastSavedDate.Value;
|
||||
CAL_LastSavedTime.Value = SAV.Played.LastSavedDate.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -237,11 +239,12 @@ namespace PKHeX.WinForms
|
|||
|
||||
SAV.OT = TB_OTName.Text;
|
||||
|
||||
SAV.Saying1 = TB_Saying1.Text;
|
||||
SAV.Saying2 = TB_Saying2.Text;
|
||||
SAV.Saying3 = TB_Saying3.Text;
|
||||
SAV.Saying4 = TB_Saying4.Text;
|
||||
SAV.Saying5 = TB_Saying5.Text;
|
||||
var status = SAV.Status;
|
||||
status.Saying1 = TB_Saying1.Text;
|
||||
status.Saying2 = TB_Saying2.Text;
|
||||
status.Saying3 = TB_Saying3.Text;
|
||||
status.Saying4 = TB_Saying4.Text;
|
||||
status.Saying5 = TB_Saying5.Text;
|
||||
|
||||
// Copy Maison Data in
|
||||
if (SAV.MaisonStats > -1)
|
||||
|
@ -251,12 +254,13 @@ namespace PKHeX.WinForms
|
|||
}
|
||||
|
||||
// Copy Position
|
||||
var sit = SAV.Situation;
|
||||
if (GB_Map.Enabled && MapUpdated)
|
||||
{
|
||||
SAV.M = (int)NUD_M.Value;
|
||||
SAV.X = (float)NUD_X.Value;
|
||||
SAV.Z = (float)NUD_Z.Value;
|
||||
SAV.Y = (float)NUD_Y.Value;
|
||||
sit.M = (int)NUD_M.Value;
|
||||
sit.X = (float)NUD_X.Value;
|
||||
sit.Z = (float)NUD_Z.Value;
|
||||
sit.Y = (float)NUD_Y.Value;
|
||||
}
|
||||
|
||||
SAV.BP = ushort.Parse(TB_BP.Text);
|
||||
|
@ -264,7 +268,7 @@ namespace PKHeX.WinForms
|
|||
SAV.SetRecord(63, Util.ToInt32(TB_PM.Text));
|
||||
// Set Max Obtained Pokémiles
|
||||
SAV.SetRecord(64, Util.ToInt32(TB_PM.Text));
|
||||
SAV.Style = byte.Parse(TB_Style.Text);
|
||||
sit.Style = byte.Parse(TB_Style.Text);
|
||||
|
||||
// Copy Badges
|
||||
int badgeval = 0;
|
||||
|
@ -281,13 +285,11 @@ namespace PKHeX.WinForms
|
|||
SAV.MultiplayerSpriteID = Convert.ToByte(CB_MultiplayerSprite.SelectedValue);
|
||||
|
||||
// Appearance
|
||||
if (SAV.XY)
|
||||
if (SAV is SAV6XY xy)
|
||||
{
|
||||
// Save Clothing Data
|
||||
var obj = (TrainerFashion6)propertyGrid1.SelectedObject;
|
||||
obj.Write(SAV.Data, SAV.TrainerCard + 0x30);
|
||||
|
||||
SAV.OT_Nick = TB_TRNick.Text;
|
||||
var xystat = (MyStatus6XY)xy.Status;
|
||||
xystat.Fashion = (TrainerFashion6)PG_CurrentAppearance.SelectedObject;
|
||||
xystat.OT_Nick = TB_TRNick.Text;
|
||||
}
|
||||
|
||||
// Vivillon
|
||||
|
@ -303,11 +305,11 @@ namespace PKHeX.WinForms
|
|||
fame += (uint)(CAL_HoFTime.Value - new DateTime(2000, 1, 1)).TotalSeconds;
|
||||
SAV.SecondsToFame = fame;
|
||||
|
||||
if (SAV.LastSavedDate.HasValue)
|
||||
SAV.LastSavedDate = new DateTime(CAL_LastSavedDate.Value.Year, CAL_LastSavedDate.Value.Month, CAL_LastSavedDate.Value.Day, CAL_LastSavedTime.Value.Hour, CAL_LastSavedTime.Value.Minute, 0);
|
||||
if (SAV.Played.LastSavedDate.HasValue)
|
||||
SAV.Played.LastSavedDate = new DateTime(CAL_LastSavedDate.Value.Year, CAL_LastSavedDate.Value.Month, CAL_LastSavedDate.Value.Day, CAL_LastSavedTime.Value.Hour, CAL_LastSavedTime.Value.Minute, 0);
|
||||
|
||||
SAV.IsMegaEvolutionUnlocked = CHK_MegaUnlocked.Checked;
|
||||
SAV.IsMegaRayquazaUnlocked = CHK_MegaRayquazaUnlocked.Checked;
|
||||
status.IsMegaEvolutionUnlocked = CHK_MegaUnlocked.Checked;
|
||||
status.IsMegaRayquazaUnlocked = CHK_MegaRayquazaUnlocked.Checked;
|
||||
}
|
||||
|
||||
private void ClickOT(object sender, MouseEventArgs e)
|
||||
|
@ -364,7 +366,8 @@ namespace PKHeX.WinForms
|
|||
|
||||
private void GiveAllAccessories(object sender, EventArgs e)
|
||||
{
|
||||
SAV.UnlockAllAccessories();
|
||||
if (SAV is SAV6XY xy)
|
||||
xy.UnlockAllAccessories();
|
||||
}
|
||||
|
||||
private void UpdateCountry(object sender, EventArgs e)
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace PKHeX.WinForms
|
|||
SAV = (SAV7)(Origin = sav).Clone();
|
||||
editing = true;
|
||||
typeMAX = SAV.USUM ? 0x7F : 0x7C;
|
||||
TB_PlazaName.Text = SAV.FestivalPlazaName;
|
||||
TB_PlazaName.Text = SAV.Festa.FestivalPlazaName;
|
||||
|
||||
if (SAV.USUM)
|
||||
{
|
||||
|
@ -36,8 +36,8 @@ namespace PKHeX.WinForms
|
|||
catch (Exception e) { WinFormsUtil.Alert("Font loading failed...", e.ToString()); }
|
||||
}
|
||||
|
||||
uint cc = SAV.FestaCoins;
|
||||
uint cu = SAV.UsedFestaCoins;
|
||||
var cc = SAV.Festa.FestaCoins;
|
||||
var cu = SAV.GetRecord(038);
|
||||
NUD_FC_Current.Value = Math.Min(cc, NUD_FC_Current.Maximum);
|
||||
NUD_FC_Used.Value = Math.Min(cu, NUD_FC_Used.Maximum);
|
||||
L_FC_CollectedV.Text = (cc + cu).ToString();
|
||||
|
@ -72,18 +72,18 @@ namespace PKHeX.WinForms
|
|||
break;
|
||||
}
|
||||
CLB_Phrases.Items.Clear();
|
||||
CLB_Phrases.Items.Add(res.Last(), SAV.GetFestaPhraseUnlocked(106)); //add Lv100 before TentPhrases
|
||||
CLB_Phrases.Items.Add(res.Last(), SAV.Festa.GetFestaPhraseUnlocked(106)); //add Lv100 before TentPhrases
|
||||
for (int i = 0; i < res.Length - 1; i++)
|
||||
CLB_Phrases.Items.Add(res[i], SAV.GetFestaPhraseUnlocked(i));
|
||||
CLB_Phrases.Items.Add(res[i], SAV.Festa.GetFestaPhraseUnlocked(i));
|
||||
|
||||
DateTime dt = SAV.FestaDate ?? new DateTime(2000, 1, 1);
|
||||
DateTime dt = SAV.Festa.FestaDate ?? new DateTime(2000, 1, 1);
|
||||
CAL_FestaStartDate.Value = CAL_FestaStartTime.Value = dt;
|
||||
|
||||
string[] res2 = { "Rank 4: missions","Rank 8: facility","Rank 10: fashion","Rank 20: rename","Rank 30: special menu","Rank 40: BGM","Rank 50: theme Glitz","Rank 60: theme Fairy","Rank 70: theme Tone","Rank 100: phrase","Current Rank", };
|
||||
CLB_Reward.Items.Clear();
|
||||
CLB_Reward.Items.Add(res2.Last(), (CheckState)RewardState[SAV.GetFestPrizeReceived(10)]); //add CurrentRank before const-rewards
|
||||
CLB_Reward.Items.Add(res2.Last(), (CheckState)RewardState[SAV.Festa.GetFestPrizeReceived(10)]); //add CurrentRank before const-rewards
|
||||
for (int i = 0; i < res2.Length - 1; i++)
|
||||
CLB_Reward.Items.Add(res2[i], (CheckState)RewardState[SAV.GetFestPrizeReceived(i)]);
|
||||
CLB_Reward.Items.Add(res2[i], (CheckState)RewardState[SAV.Festa.GetFestPrizeReceived(i)]);
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
f[i] = new FestaFacility(SAV, i);
|
||||
|
@ -149,11 +149,11 @@ namespace PKHeX.WinForms
|
|||
CB_LuckyResult.Items.Add($"{lv} {type}");
|
||||
}
|
||||
|
||||
NUD_Rank.Value = SAV.FestaRank;
|
||||
LoadRankLabel(SAV.FestaRank);
|
||||
NUD_Rank.Value = SAV.Festa.FestaRank;
|
||||
LoadRankLabel(SAV.Festa.FestaRank);
|
||||
NUD_Messages = new[] { NUD_MyMessageMeet, NUD_MyMessagePart, NUD_MyMessageMoved, NUD_MyMessageDissapointed };
|
||||
for (int i = 0; i < NUD_Messages.Length; i++)
|
||||
NUD_Messages[i].Value = SAV.GetFestaMessage(i);
|
||||
NUD_Messages[i].Value = SAV.Festa.GetFestaMessage(i);
|
||||
|
||||
LB_FacilityIndex.SelectedIndex = 0;
|
||||
CB_FacilityMessage.SelectedIndex = 0;
|
||||
|
@ -256,17 +256,17 @@ namespace PKHeX.WinForms
|
|||
|
||||
private void Save()
|
||||
{
|
||||
SAV.SetFestaPhraseUnlocked(106, CLB_Phrases.GetItemChecked(0));
|
||||
SAV.Festa.SetFestaPhraseUnlocked(106, CLB_Phrases.GetItemChecked(0));
|
||||
for (int i = 1; i < CLB_Phrases.Items.Count; i++)
|
||||
SAV.SetFestaPhraseUnlocked(i - 1, CLB_Phrases.GetItemChecked(i));
|
||||
SAV.Festa.SetFestaPhraseUnlocked(i - 1, CLB_Phrases.GetItemChecked(i));
|
||||
|
||||
SAV.UsedFestaCoins = (uint)NUD_FC_Used.Value;
|
||||
SAV.FestaCoins = (uint)NUD_FC_Current.Value;
|
||||
SAV.FestaDate = new DateTime(CAL_FestaStartDate.Value.Year, CAL_FestaStartDate.Value.Month, CAL_FestaStartDate.Value.Day, CAL_FestaStartTime.Value.Hour, CAL_FestaStartTime.Value.Minute, CAL_FestaStartTime.Value.Second);
|
||||
SAV.SetRecord(038, (int)NUD_FC_Used.Value);
|
||||
SAV.Festa.FestaCoins = (int)NUD_FC_Current.Value;
|
||||
SAV.Festa.FestaDate = new DateTime(CAL_FestaStartDate.Value.Year, CAL_FestaStartDate.Value.Month, CAL_FestaStartDate.Value.Day, CAL_FestaStartTime.Value.Hour, CAL_FestaStartTime.Value.Minute, CAL_FestaStartTime.Value.Second);
|
||||
|
||||
SAV.SetFestaPrizeReceived(10, RewardState[(int)CLB_Reward.GetItemCheckState(0)]);
|
||||
SAV.Festa.SetFestaPrizeReceived(10, RewardState[(int)CLB_Reward.GetItemCheckState(0)]);
|
||||
for (int i = 1; i < CLB_Reward.Items.Count; i++)
|
||||
SAV.SetFestaPrizeReceived(i - 1, RewardState[(int)CLB_Reward.GetItemCheckState(i)]);
|
||||
SAV.Festa.SetFestaPrizeReceived(i - 1, RewardState[(int)CLB_Reward.GetItemCheckState(i)]);
|
||||
|
||||
SaveFacility();
|
||||
foreach (FestaFacility facility in f)
|
||||
|
@ -330,7 +330,7 @@ namespace PKHeX.WinForms
|
|||
SAV.SetData(BitConverter.GetBytes((ushort)NUD_DefeatMon.Value), 0x6C558);
|
||||
for (int i = 0; i < NUD_Trainers.Length; i++)
|
||||
SAV.SetData(BitConverter.GetBytes((ushort)NUD_Trainers[i].Value), 0x6C56C + (0x14 * i));
|
||||
SAV.FestivalPlazaName = TB_PlazaName.Text;
|
||||
SAV.Festa.FestivalPlazaName = TB_PlazaName.Text;
|
||||
}
|
||||
|
||||
private void NUD_FC_ValueChanged(object sender, EventArgs e)
|
||||
|
@ -567,7 +567,7 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
if (editing) return;
|
||||
int rank = (int)NUD_Rank.Value;
|
||||
SAV.FestaRank = (ushort)rank;
|
||||
SAV.Festa.FestaRank = (ushort)rank;
|
||||
LoadRankLabel(rank);
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ namespace PKHeX.WinForms
|
|||
if (editing) return;
|
||||
int mmIndex = Array.IndexOf(NUD_Messages, (NumericUpDown)sender);
|
||||
if (mmIndex < 0) return;
|
||||
SAV.SetFestaMessage(mmIndex, (ushort)((NumericUpDown)sender).Value);
|
||||
SAV.Festa.SetFestaMessage(mmIndex, (ushort)((NumericUpDown)sender).Value);
|
||||
}
|
||||
|
||||
private void CHK_FacilityIntroduced_CheckedChanged(object sender, EventArgs e)
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace PKHeX.WinForms
|
|||
}
|
||||
|
||||
if (SAV.USUM)
|
||||
TB_EC.Text = SAV.StarterEncryptionConstant.ToString("X8");
|
||||
TB_EC.Text = SAV.MiscBlock.StarterEncryptionConstant.ToString("X8");
|
||||
else
|
||||
TB_EC.Visible = L_EC.Visible = false;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ namespace PKHeX.WinForms
|
|||
}
|
||||
|
||||
if (SAV.USUM)
|
||||
SAV.StarterEncryptionConstant = Util.GetHexValue(TB_EC.Text);
|
||||
SAV.MiscBlock.StarterEncryptionConstant = Util.GetHexValue(TB_EC.Text);
|
||||
|
||||
Origin.SetData(SAV.Data, 0);
|
||||
Close();
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace PKHeX.WinForms
|
|||
CB_Region.SelectedValue = SAV.SubRegion;
|
||||
CB_3DSReg.SelectedValue = SAV.ConsoleRegion;
|
||||
CB_Language.SelectedValue = SAV.Language;
|
||||
var time = SAV.AlolaTime;
|
||||
var time = SAV.GameTime.AlolaTime;
|
||||
if (time == 0)
|
||||
time = 24 * 60 * 60; // Patch up any bad times from previous program versions.
|
||||
if (time == 9_999_999)
|
||||
|
@ -121,14 +121,14 @@ namespace PKHeX.WinForms
|
|||
if (CB_AlolaTime.SelectedValue == null)
|
||||
CB_AlolaTime.Enabled = false;
|
||||
|
||||
NUD_M.Value = SAV.M;
|
||||
NUD_M.Value = SAV.Situation.M;
|
||||
// Sanity Check Map Coordinates
|
||||
try
|
||||
{
|
||||
NUD_X.Value = (decimal)SAV.X;
|
||||
NUD_Z.Value = (decimal)SAV.Z;
|
||||
NUD_Y.Value = (decimal)SAV.Y;
|
||||
NUD_R.Value = (decimal)SAV.R;
|
||||
NUD_X.Value = (decimal)SAV.Situation.X;
|
||||
NUD_Z.Value = (decimal)SAV.Situation.Z;
|
||||
NUD_Y.Value = (decimal)SAV.Situation.Y;
|
||||
NUD_R.Value = (decimal)SAV.Situation.R;
|
||||
}
|
||||
catch { GB_Map.Enabled = false; }
|
||||
|
||||
|
@ -137,10 +137,10 @@ namespace PKHeX.WinForms
|
|||
MT_Minutes.Text = SAV.PlayedMinutes.ToString();
|
||||
MT_Seconds.Text = SAV.PlayedSeconds.ToString();
|
||||
|
||||
if (SAV.LastSavedDate.HasValue)
|
||||
if (SAV.Played.LastSavedDate.HasValue)
|
||||
{
|
||||
CAL_LastSavedDate.Value = SAV.LastSavedDate.Value;
|
||||
CAL_LastSavedTime.Value = SAV.LastSavedDate.Value;
|
||||
CAL_LastSavedDate.Value = SAV.Played.LastSavedDate.Value;
|
||||
CAL_LastSavedTime.Value = SAV.Played.LastSavedDate.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -153,47 +153,48 @@ namespace PKHeX.WinForms
|
|||
CAL_HoFDate.Value = epoch.AddSeconds(SAV.SecondsToFame);
|
||||
CAL_HoFTime.Value = epoch.AddSeconds(SAV.SecondsToFame % 86400);
|
||||
|
||||
NUD_BP.Value = Math.Min(NUD_BP.Maximum, SAV.BP);
|
||||
NUD_FC.Value = Math.Min(NUD_FC.Maximum, SAV.FestaCoins);
|
||||
NUD_BP.Value = Math.Min(NUD_BP.Maximum, SAV.MiscBlock.BP);
|
||||
NUD_FC.Value = Math.Min(NUD_FC.Maximum, SAV.Festa.FestaCoins);
|
||||
|
||||
// Poké Finder
|
||||
NUD_SnapCount.Value = Math.Min(NUD_SnapCount.Maximum, SAV.PokeFinderSnapCount);
|
||||
NUD_ThumbsTotal.Value = Math.Min(NUD_ThumbsTotal.Maximum, SAV.PokeFinderThumbsTotalValue);
|
||||
NUD_ThumbsRecord.Value = Math.Min(NUD_ThumbsRecord.Maximum, SAV.PokeFinderThumbsHighValue);
|
||||
NUD_SnapCount.Value = Math.Min(NUD_SnapCount.Maximum, SAV.PokeFinder.SnapCount);
|
||||
NUD_ThumbsTotal.Value = Math.Min(NUD_ThumbsTotal.Maximum, SAV.PokeFinder.ThumbsTotalValue);
|
||||
NUD_ThumbsRecord.Value = Math.Min(NUD_ThumbsRecord.Maximum, SAV.PokeFinder.ThumbsHighValue);
|
||||
|
||||
CB_CameraVersion.SelectedIndex = Math.Min(CB_CameraVersion.Items.Count - 1, SAV.PokeFinderCameraVersion);
|
||||
CHK_Gyro.Checked = SAV.PokeFinderGyroFlag;
|
||||
CB_CameraVersion.SelectedIndex = Math.Min(CB_CameraVersion.Items.Count - 1, SAV.PokeFinder.CameraVersion);
|
||||
CHK_Gyro.Checked = SAV.PokeFinder.GyroFlag;
|
||||
|
||||
// Battle Tree
|
||||
NUD_RCStreak0.Value = Math.Min(NUD_RCStreak0.Maximum, SAV.GetTreeStreak(0, super: false, max: false));
|
||||
NUD_RCStreak1.Value = Math.Min(NUD_RCStreak1.Maximum, SAV.GetTreeStreak(1, super: false, max: false));
|
||||
NUD_RCStreak2.Value = Math.Min(NUD_RCStreak2.Maximum, SAV.GetTreeStreak(2, super: false, max: false));
|
||||
NUD_RMStreak0.Value = Math.Min(NUD_RMStreak0.Maximum, SAV.GetTreeStreak(0, super: false, max: true));
|
||||
NUD_RMStreak1.Value = Math.Min(NUD_RMStreak1.Maximum, SAV.GetTreeStreak(1, super: false, max: true));
|
||||
NUD_RMStreak2.Value = Math.Min(NUD_RMStreak2.Maximum, SAV.GetTreeStreak(2, super: false, max: true));
|
||||
var bt = SAV.BattleTreeBlock;
|
||||
NUD_RCStreak0.Value = Math.Min(NUD_RCStreak0.Maximum, bt.GetTreeStreak(0, super: false, max: false));
|
||||
NUD_RCStreak1.Value = Math.Min(NUD_RCStreak1.Maximum, bt.GetTreeStreak(1, super: false, max: false));
|
||||
NUD_RCStreak2.Value = Math.Min(NUD_RCStreak2.Maximum, bt.GetTreeStreak(2, super: false, max: false));
|
||||
NUD_RMStreak0.Value = Math.Min(NUD_RMStreak0.Maximum, bt.GetTreeStreak(0, super: false, max: true));
|
||||
NUD_RMStreak1.Value = Math.Min(NUD_RMStreak1.Maximum, bt.GetTreeStreak(1, super: false, max: true));
|
||||
NUD_RMStreak2.Value = Math.Min(NUD_RMStreak2.Maximum, bt.GetTreeStreak(2, super: false, max: true));
|
||||
|
||||
NUD_SCStreak0.Value = Math.Min(NUD_SCStreak0.Maximum, SAV.GetTreeStreak(0, super: true, max: false));
|
||||
NUD_SCStreak1.Value = Math.Min(NUD_SCStreak1.Maximum, SAV.GetTreeStreak(1, super: true, max: false));
|
||||
NUD_SCStreak2.Value = Math.Min(NUD_SCStreak2.Maximum, SAV.GetTreeStreak(2, super: true, max: false));
|
||||
NUD_SMStreak0.Value = Math.Min(NUD_SMStreak0.Maximum, SAV.GetTreeStreak(0, super: true, max: true));
|
||||
NUD_SMStreak1.Value = Math.Min(NUD_SMStreak1.Maximum, SAV.GetTreeStreak(1, super: true, max: true));
|
||||
NUD_SMStreak2.Value = Math.Min(NUD_SMStreak2.Maximum, SAV.GetTreeStreak(2, super: true, max: true));
|
||||
NUD_SCStreak0.Value = Math.Min(NUD_SCStreak0.Maximum, bt.GetTreeStreak(0, super: true, max: false));
|
||||
NUD_SCStreak1.Value = Math.Min(NUD_SCStreak1.Maximum, bt.GetTreeStreak(1, super: true, max: false));
|
||||
NUD_SCStreak2.Value = Math.Min(NUD_SCStreak2.Maximum, bt.GetTreeStreak(2, super: true, max: false));
|
||||
NUD_SMStreak0.Value = Math.Min(NUD_SMStreak0.Maximum, bt.GetTreeStreak(0, super: true, max: true));
|
||||
NUD_SMStreak1.Value = Math.Min(NUD_SMStreak1.Maximum, bt.GetTreeStreak(1, super: true, max: true));
|
||||
NUD_SMStreak2.Value = Math.Min(NUD_SMStreak2.Maximum, bt.GetTreeStreak(2, super: true, max: true));
|
||||
|
||||
CB_SkinColor.SelectedIndex = SAV.DressUpSkinColor;
|
||||
TB_PlazaName.Text = SAV.FestivalPlazaName;
|
||||
CB_SkinColor.SelectedIndex = SAV.MyStatus.DressUpSkinColor;
|
||||
TB_PlazaName.Text = SAV.Festa.FestivalPlazaName;
|
||||
|
||||
CB_Vivillon.SelectedIndex = (SAV.Vivillon < CB_Vivillon.Items.Count) ? SAV.Vivillon : -1;
|
||||
NUD_DaysFromRefreshed.Value = Math.Min(NUD_DaysFromRefreshed.Maximum, SAV.DaysFromRefreshed);
|
||||
CB_Vivillon.SelectedIndex = (SAV.MiscBlock.Vivillon < CB_Vivillon.Items.Count) ? SAV.MiscBlock.Vivillon : -1;
|
||||
NUD_DaysFromRefreshed.Value = Math.Min(NUD_DaysFromRefreshed.Maximum, SAV.MiscBlock.DaysFromRefreshed);
|
||||
|
||||
if (SAV.BallThrowType >= 0 && SAV.BallThrowType < CB_BallThrowType.Items.Count)
|
||||
CB_BallThrowType.SelectedIndex = SAV.BallThrowType;
|
||||
if (SAV.MyStatus.BallThrowType >= 0 && SAV.MyStatus.BallThrowType < CB_BallThrowType.Items.Count)
|
||||
CB_BallThrowType.SelectedIndex = SAV.MyStatus.BallThrowType;
|
||||
|
||||
if (SAV.SM)
|
||||
LoadThrowTypeLists();
|
||||
else
|
||||
CB_BallThrowTypeListMode.Visible = LB_BallThrowTypeLearned.Visible = LB_BallThrowTypeUnlocked.Visible = false;
|
||||
|
||||
uint stampBits = SAV.Stamps;
|
||||
uint stampBits = SAV.MiscBlock.Stamps;
|
||||
for (int i = 0; i < LB_Stamps.Items.Count; i++)
|
||||
LB_Stamps.SetSelected(i, (stampBits & (1 << i)) != 0);
|
||||
|
||||
|
@ -201,8 +202,8 @@ namespace PKHeX.WinForms
|
|||
CHK_UnlockSuperDoubles.Checked = SAV.GetEventFlag(334);
|
||||
CHK_UnlockSuperMulti.Checked = SAV.GetEventFlag(335);
|
||||
|
||||
CHK_UnlockMega.Checked = SAV.MegaUnlocked;
|
||||
CHK_UnlockZMove.Checked = SAV.ZMoveUnlocked;
|
||||
CHK_UnlockMega.Checked = SAV.MyStatus.MegaUnlocked;
|
||||
CHK_UnlockZMove.Checked = SAV.MyStatus.ZMoveUnlocked;
|
||||
|
||||
LoadMapFlyToData();
|
||||
}
|
||||
|
@ -289,12 +290,12 @@ namespace PKHeX.WinForms
|
|||
|
||||
private void LoadUltraData()
|
||||
{
|
||||
NUD_Surf0.Value = SAV.GetSurfScore(0);
|
||||
NUD_Surf1.Value = SAV.GetSurfScore(1);
|
||||
NUD_Surf2.Value = SAV.GetSurfScore(2);
|
||||
NUD_Surf3.Value = SAV.GetSurfScore(3);
|
||||
NUD_Surf0.Value = SAV.MiscBlock.GetSurfScore(0);
|
||||
NUD_Surf1.Value = SAV.MiscBlock.GetSurfScore(1);
|
||||
NUD_Surf2.Value = SAV.MiscBlock.GetSurfScore(2);
|
||||
NUD_Surf3.Value = SAV.MiscBlock.GetSurfScore(3);
|
||||
TB_RotomOT.Font = TB_OTName.Font;
|
||||
TB_RotomOT.Text = SAV.RotomOT;
|
||||
TB_RotomOT.Text = SAV.FieldMenu.RotomOT;
|
||||
}
|
||||
|
||||
private void Save()
|
||||
|
@ -303,13 +304,13 @@ namespace PKHeX.WinForms
|
|||
SavePokeFinder();
|
||||
SaveBattleTree();
|
||||
SaveTrainerAppearance();
|
||||
SAV.DaysFromRefreshed = (byte)NUD_DaysFromRefreshed.Value;
|
||||
SAV.MiscBlock.DaysFromRefreshed = (byte)NUD_DaysFromRefreshed.Value;
|
||||
SaveThrowType();
|
||||
|
||||
SAV.FestivalPlazaName = TB_PlazaName.Text;
|
||||
SAV.Festa.FestivalPlazaName = TB_PlazaName.Text;
|
||||
|
||||
// Vivillon
|
||||
if (CB_Vivillon.SelectedIndex >= 0) SAV.Vivillon = CB_Vivillon.SelectedIndex;
|
||||
if (CB_Vivillon.SelectedIndex >= 0) SAV.MiscBlock.Vivillon = CB_Vivillon.SelectedIndex;
|
||||
|
||||
SaveFlags();
|
||||
|
||||
|
@ -328,18 +329,19 @@ namespace PKHeX.WinForms
|
|||
SAV.ConsoleRegion = WinFormsUtil.GetIndex(CB_3DSReg);
|
||||
SAV.Language = WinFormsUtil.GetIndex(CB_Language);
|
||||
if (CB_AlolaTime.Enabled)
|
||||
SAV.AlolaTime = (ulong)WinFormsUtil.GetIndex(CB_AlolaTime);
|
||||
SAV.GameTime.AlolaTime = (ulong)WinFormsUtil.GetIndex(CB_AlolaTime);
|
||||
|
||||
SAV.OT = TB_OTName.Text;
|
||||
|
||||
// Copy Position
|
||||
if (GB_Map.Enabled && MapUpdated)
|
||||
{
|
||||
SAV.M = (int)NUD_M.Value;
|
||||
SAV.X = (float)NUD_X.Value;
|
||||
SAV.Z = (float)NUD_Z.Value;
|
||||
SAV.Y = (float)NUD_Y.Value;
|
||||
SAV.R = (float)NUD_R.Value;
|
||||
SAV.Situation.M = (int)NUD_M.Value;
|
||||
SAV.Situation.X = (float)NUD_X.Value;
|
||||
SAV.Situation.Z = (float)NUD_Z.Value;
|
||||
SAV.Situation.Y = (float)NUD_Y.Value;
|
||||
SAV.Situation.R = (float)NUD_R.Value;
|
||||
SAV.Situation.UpdateOverworldCoordinates();
|
||||
}
|
||||
|
||||
// Save PlayTime
|
||||
|
@ -358,38 +360,39 @@ namespace PKHeX.WinForms
|
|||
fame += (uint)(CAL_HoFTime.Value - epoch).TotalSeconds;
|
||||
SAV.SecondsToFame = fame;
|
||||
|
||||
if (SAV.LastSavedDate.HasValue)
|
||||
SAV.LastSavedDate = new DateTime(CAL_LastSavedDate.Value.Year, CAL_LastSavedDate.Value.Month, CAL_LastSavedDate.Value.Day, CAL_LastSavedTime.Value.Hour, CAL_LastSavedTime.Value.Minute, 0);
|
||||
if (SAV.Played.LastSavedDate.HasValue)
|
||||
SAV.Played.LastSavedDate = new DateTime(CAL_LastSavedDate.Value.Year, CAL_LastSavedDate.Value.Month, CAL_LastSavedDate.Value.Day, CAL_LastSavedTime.Value.Hour, CAL_LastSavedTime.Value.Minute, 0);
|
||||
|
||||
SAV.BP = (uint)NUD_BP.Value;
|
||||
SAV.FestaCoins = (uint)NUD_FC.Value;
|
||||
SAV.MiscBlock.BP = (uint)NUD_BP.Value;
|
||||
SAV.Festa.FestaCoins = (int)NUD_FC.Value;
|
||||
}
|
||||
|
||||
private void SavePokeFinder()
|
||||
{
|
||||
SAV.PokeFinderSnapCount = (uint)NUD_SnapCount.Value;
|
||||
SAV.PokeFinderThumbsTotalValue = (uint)NUD_ThumbsTotal.Value;
|
||||
SAV.PokeFinderThumbsHighValue = (uint)NUD_ThumbsRecord.Value;
|
||||
SAV.PokeFinder.SnapCount = (uint)NUD_SnapCount.Value;
|
||||
SAV.PokeFinder.ThumbsTotalValue = (uint)NUD_ThumbsTotal.Value;
|
||||
SAV.PokeFinder.ThumbsHighValue = (uint)NUD_ThumbsRecord.Value;
|
||||
|
||||
SAV.PokeFinderCameraVersion = (ushort)CB_CameraVersion.SelectedIndex;
|
||||
SAV.PokeFinderGyroFlag = CHK_Gyro.Checked;
|
||||
SAV.PokeFinder.CameraVersion = (ushort)CB_CameraVersion.SelectedIndex;
|
||||
SAV.PokeFinder.GyroFlag = CHK_Gyro.Checked;
|
||||
}
|
||||
|
||||
private void SaveBattleTree()
|
||||
{
|
||||
SAV.SetTreeStreak((int)NUD_RCStreak0.Value, 0, super:false, max:false);
|
||||
SAV.SetTreeStreak((int)NUD_RCStreak1.Value, 1, super:false, max:false);
|
||||
SAV.SetTreeStreak((int)NUD_RCStreak2.Value, 2, super:false, max:false);
|
||||
SAV.SetTreeStreak((int)NUD_RMStreak0.Value, 0, super:false, max:true);
|
||||
SAV.SetTreeStreak((int)NUD_RMStreak1.Value, 1, super:false, max:true);
|
||||
SAV.SetTreeStreak((int)NUD_RMStreak2.Value, 2, super:false, max:true);
|
||||
var bt = SAV.BattleTreeBlock;
|
||||
bt.SetTreeStreak((int)NUD_RCStreak0.Value, 0, super:false, max:false);
|
||||
bt.SetTreeStreak((int)NUD_RCStreak1.Value, 1, super:false, max:false);
|
||||
bt.SetTreeStreak((int)NUD_RCStreak2.Value, 2, super:false, max:false);
|
||||
bt.SetTreeStreak((int)NUD_RMStreak0.Value, 0, super:false, max:true);
|
||||
bt.SetTreeStreak((int)NUD_RMStreak1.Value, 1, super:false, max:true);
|
||||
bt.SetTreeStreak((int)NUD_RMStreak2.Value, 2, super:false, max:true);
|
||||
|
||||
SAV.SetTreeStreak((int)NUD_SCStreak0.Value, 0, super:true, max:false);
|
||||
SAV.SetTreeStreak((int)NUD_SCStreak1.Value, 1, super:true, max:false);
|
||||
SAV.SetTreeStreak((int)NUD_SCStreak2.Value, 2, super:true, max:false);
|
||||
SAV.SetTreeStreak((int)NUD_SMStreak0.Value, 0, super:true, max:true);
|
||||
SAV.SetTreeStreak((int)NUD_SMStreak1.Value, 1, super:true, max:true);
|
||||
SAV.SetTreeStreak((int)NUD_SMStreak2.Value, 2, super:true, max:true);
|
||||
bt.SetTreeStreak((int)NUD_SCStreak0.Value, 0, super:true, max:false);
|
||||
bt.SetTreeStreak((int)NUD_SCStreak1.Value, 1, super:true, max:false);
|
||||
bt.SetTreeStreak((int)NUD_SCStreak2.Value, 2, super:true, max:false);
|
||||
bt.SetTreeStreak((int)NUD_SMStreak0.Value, 0, super:true, max:true);
|
||||
bt.SetTreeStreak((int)NUD_SMStreak1.Value, 1, super:true, max:true);
|
||||
bt.SetTreeStreak((int)NUD_SMStreak2.Value, 2, super:true, max:true);
|
||||
}
|
||||
|
||||
private void SaveTrainerAppearance()
|
||||
|
@ -400,17 +403,17 @@ namespace PKHeX.WinForms
|
|||
string gStr = CB_Gender.Items[gender].ToString();
|
||||
string sStr = CB_Gender.Items[skin].ToString();
|
||||
|
||||
if (SAV.DressUpSkinColor == CB_SkinColor.SelectedIndex)
|
||||
if (SAV.MyStatus.DressUpSkinColor == CB_SkinColor.SelectedIndex)
|
||||
return;
|
||||
|
||||
if (SAV.Gender == skin || DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, $"Gender-Skin mismatch:{Environment.NewLine}Gender: {gStr}, Skin: {sStr}", "Save selected Skin Color?"))
|
||||
SAV.DressUpSkinColor = CB_SkinColor.SelectedIndex;
|
||||
SAV.MyStatus.DressUpSkinColor = CB_SkinColor.SelectedIndex;
|
||||
}
|
||||
|
||||
private void SaveThrowType()
|
||||
{
|
||||
if (CB_BallThrowType.SelectedIndex >= 0)
|
||||
SAV.BallThrowType = CB_BallThrowType.SelectedIndex;
|
||||
SAV.MyStatus.BallThrowType = CB_BallThrowType.SelectedIndex;
|
||||
|
||||
if (!SAV.SM) // unlock flags are in flag editor instead
|
||||
return;
|
||||
|
@ -425,14 +428,14 @@ namespace PKHeX.WinForms
|
|||
|
||||
private void SaveFlags()
|
||||
{
|
||||
SAV.Stamps = GetBits(LB_Stamps);
|
||||
SAV.MiscBlock.Stamps = GetBits(LB_Stamps);
|
||||
|
||||
SAV.SetEventFlag(333, CHK_UnlockSuperSingles.Checked);
|
||||
SAV.SetEventFlag(334, CHK_UnlockSuperDoubles.Checked);
|
||||
SAV.SetEventFlag(335, CHK_UnlockSuperMulti.Checked);
|
||||
|
||||
SAV.MegaUnlocked = CHK_UnlockMega.Checked;
|
||||
SAV.ZMoveUnlocked = CHK_UnlockZMove.Checked;
|
||||
SAV.MyStatus.MegaUnlocked = CHK_UnlockMega.Checked;
|
||||
SAV.MyStatus.ZMoveUnlocked = CHK_UnlockZMove.Checked;
|
||||
|
||||
for (int i = 0; i < CLB_FlyDest.Items.Count; i++)
|
||||
SAV.SetEventFlag(SkipFlag + FlyDestFlagOfs[i], CLB_FlyDest.GetItemChecked(i));
|
||||
|
@ -442,21 +445,21 @@ namespace PKHeX.WinForms
|
|||
|
||||
private void SaveUltraData()
|
||||
{
|
||||
SAV.SetSurfScore(0, (int)NUD_Surf0.Value);
|
||||
SAV.SetSurfScore(1, (int)NUD_Surf1.Value);
|
||||
SAV.SetSurfScore(2, (int)NUD_Surf2.Value);
|
||||
SAV.SetSurfScore(3, (int)NUD_Surf3.Value);
|
||||
SAV.MiscBlock.SetSurfScore(0, (int)NUD_Surf0.Value);
|
||||
SAV.MiscBlock.SetSurfScore(1, (int)NUD_Surf1.Value);
|
||||
SAV.MiscBlock.SetSurfScore(2, (int)NUD_Surf2.Value);
|
||||
SAV.MiscBlock.SetSurfScore(3, (int)NUD_Surf3.Value);
|
||||
|
||||
if (TB_RotomOT.Text != TB_OTName.Text // different Rotom name from OT
|
||||
&& TB_OTName.Text != SAV.OT // manually changed
|
||||
&& DialogResult.Yes == // wants to update
|
||||
WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Rotom OT does not match OT name. Update Rotom OT name with OT name?"))
|
||||
{
|
||||
SAV.RotomOT = TB_OTName.Text;
|
||||
SAV.FieldMenu.RotomOT = TB_OTName.Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
SAV.RotomOT = TB_RotomOT.Text;
|
||||
SAV.FieldMenu.RotomOT = TB_RotomOT.Text;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +532,7 @@ namespace PKHeX.WinForms
|
|||
return;
|
||||
|
||||
// Clear Block
|
||||
new byte[SAV.FashionLength].CopyTo(SAV.Data, SAV.Fashion);
|
||||
SAV.FashionBlock.Clear();
|
||||
|
||||
// Write Payload
|
||||
// Every fashion item is 2 bits, New Flag (high) & Owned Flag (low)
|
||||
|
|
|
@ -135,14 +135,14 @@ namespace PKHeX.WinForms
|
|||
control.Visible = true;
|
||||
}
|
||||
L_Coins.Text = "BP"; // no translation boo
|
||||
MT_Coins.Text = s.BP.ToString();
|
||||
MT_Coins.Text = s.BattleSubwayBlock.BP.ToString();
|
||||
|
||||
NUD_M.Value = s.M;
|
||||
NUD_X.Value = s.X;
|
||||
NUD_Z.Value = s.Z;
|
||||
NUD_Y.Value = s.Y;
|
||||
|
||||
badgeval = s.Badges;
|
||||
var pd = s.PlayerData;
|
||||
NUD_M.Value = pd.M;
|
||||
NUD_X.Value = pd.X;
|
||||
NUD_Z.Value = pd.Z;
|
||||
NUD_Y.Value = pd.Y;
|
||||
badgeval = s.MiscBlock.Badges;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cba.Length; i++)
|
||||
|
@ -242,13 +242,14 @@ namespace PKHeX.WinForms
|
|||
{
|
||||
if (MapUpdated)
|
||||
{
|
||||
s.M = (int)NUD_M.Value;
|
||||
s.X = (int)NUD_X.Value;
|
||||
s.Z = (int)NUD_Z.Value;
|
||||
s.Y = (int)NUD_Y.Value;
|
||||
var pd = s.PlayerData;
|
||||
pd.M = (int)NUD_M.Value;
|
||||
pd.X = (int)NUD_X.Value;
|
||||
pd.Z = (int)NUD_Z.Value;
|
||||
pd.Y = (int)NUD_Y.Value;
|
||||
}
|
||||
s.Badges = badgeval & 0xFF;
|
||||
s.BP = (ushort)Math.Min(Util.ToUInt32(MT_Coins.Text), SAV.MaxCoins);
|
||||
s.MiscBlock.Badges = badgeval & 0xFF;
|
||||
s.BattleSubwayBlock.BP = (ushort)Math.Min(Util.ToUInt32(MT_Coins.Text), SAV.MaxCoins);
|
||||
}
|
||||
|
||||
SAV.SecondsToStart = GetSeconds(CAL_AdventureStartDate, CAL_AdventureStartTime);
|
||||
|
@ -265,9 +266,10 @@ namespace PKHeX.WinForms
|
|||
|
||||
private static uint GetSeconds(DateTimePicker date, DateTimePicker time)
|
||||
{
|
||||
uint val = (uint)(date.Value - new DateTime(2000, 1, 1)).TotalSeconds;
|
||||
var epoch = new DateTime(2000, 1, 1);
|
||||
uint val = (uint)(date.Value - epoch).TotalSeconds;
|
||||
val -= val % 86400;
|
||||
val += (uint)(time.Value - new DateTime(2000, 1, 1)).TotalSeconds;
|
||||
val += (uint)(time.Value - epoch).TotalSeconds;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace PKHeX.Tests.Saves
|
|||
{
|
||||
var folder = TestUtil.GetRepoPath();
|
||||
var path = Path.Combine(folder, "TestData", "SM Project 802.main");
|
||||
return new SAV7(File.ReadAllBytes(path));
|
||||
return new SAV7SM(File.ReadAllBytes(path));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -25,7 +25,7 @@ namespace PKHeX.Tests.Saves
|
|||
{
|
||||
var save = GetSave();
|
||||
var originalChecksumInfo = save.ChecksumInfo;
|
||||
var newSave = new SAV7(save.Write());
|
||||
var newSave = new SAV7SM(save.Write());
|
||||
|
||||
save.ChecksumInfo.Should().BeEquivalentTo(originalChecksumInfo, "because the checksum should have been modified");
|
||||
save.ChecksumsValid.Should().BeTrue("because the checksum should be valid after write");
|
||||
|
|
Loading…
Reference in a new issue