PKHeX/Saves/SAV4.cs
Kaphotics 54bc0b320d Add PersonalInfo for gens4/5
Abstracted the PersonalInfo class to the multi-generation format.
Structure hasn't changed since BW sans a few additions.
2016-07-02 20:24:17 -07:00

671 lines
27 KiB
C#

using System;
using System.Linq;
namespace PKHeX
{
public sealed class SAV4 : SaveFile
{
public override string BAKName => $"{FileName} [{OT} ({Version})" +/* - {LastSavedTime}*/ "].bak";
public override string Filter => (Footer.Length > 0 ? "DeSmuME DSV|*.dsv|" : "") + "SAV File|*.sav";
public override string Extension => ".sav";
public SAV4(byte[] data = null, GameVersion versionOverride = GameVersion.Any)
{
Data = data == null ? new byte[SaveUtil.SIZE_G4RAW] : (byte[])data.Clone();
BAK = (byte[])Data.Clone();
Exportable = !Data.SequenceEqual(new byte[Data.Length]);
// Get Version
if (data == null)
Version = GameVersion.HGSS;
else if (versionOverride != GameVersion.Any)
Version = versionOverride;
else Version = SaveUtil.getIsG4SAV(Data);
if (Version == GameVersion.Invalid)
return;
getActiveBlock();
getSAVOffsets();
switch (Version)
{
case GameVersion.DP: Personal = Legal.PersonalDP; break;
case GameVersion.Pt: Personal = Legal.PersonalPt; break;
case GameVersion.HGSS: Personal = Legal.PersonalHGSS; break;
}
if (!Exportable)
resetBoxes();
}
// Configuration
public override SaveFile Clone() { return new SAV4(Data, Version); }
public override int SIZE_STORED => PKX.SIZE_4STORED;
public override int SIZE_PARTY => PKX.SIZE_4PARTY;
public override PKM BlankPKM => new PK4();
protected override Type PKMType => typeof(PK4);
public override int BoxCount => 18;
public override int MaxEV => 255;
public override int Generation => 4;
protected override int EventFlagMax => int.MinValue;
protected override int EventConstMax => int.MinValue;
protected override int GiftCountMax => 11;
public override int OTLength => 8;
public override int NickLength => 10;
public override int MaxMoveID => 467;
public override int MaxSpeciesID => 493;
public override int MaxItemID => Version == GameVersion.HGSS ? 536 : Version == GameVersion.Pt ? 467 : 464;
public override int MaxAbilityID => 123;
public override int MaxBallID => 0x18;
public override int MaxGameID => 15; // Colo/XD
// Checksums
protected override void setChecksums()
{
switch (Version)
{
case GameVersion.DP:
// 0x0000-0xC0EC @ 0xC0FE
// 0xc100-0x1E2CC @ 0x1E2DE
BitConverter.GetBytes(SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xC0EC).ToArray())).CopyTo(Data, 0xC0FE + GBO);
BitConverter.GetBytes(SaveUtil.ccitt16(Data.Skip(0xc100 + SBO).Take(0x121CC).ToArray())).CopyTo(Data, 0x1E2DE + SBO);
break;
case GameVersion.Pt:
// 0x0000-0xCF18 @ 0xCF2A
// 0xCF2C-0x1F0FC @ 0x1F10E
BitConverter.GetBytes(SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xCF18).ToArray())).CopyTo(Data, 0xCF2A + GBO);
BitConverter.GetBytes(SaveUtil.ccitt16(Data.Skip(0xCF2C + SBO).Take(0x121D0).ToArray())).CopyTo(Data, 0x1F10E + SBO);
break;
case GameVersion.HGSS:
// 0x0000-0xF618 @ 0xF626
// 0xF700-0x219FC @ 0x21A0E
BitConverter.GetBytes(SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xF618).ToArray())).CopyTo(Data, 0xF626 + GBO);
BitConverter.GetBytes(SaveUtil.ccitt16(Data.Skip(0xF700 + SBO).Take(0x12300).ToArray())).CopyTo(Data, 0x21A0E + SBO);
break;
}
}
public override bool ChecksumsValid
{
get
{
switch (Version)
{
case GameVersion.DP:
// 0x0000-0xC0EC @ 0xC0FE
// 0xc100-0x1E2CC @ 0x1E2DE
if (SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xC0EC).ToArray()) != BitConverter.ToUInt16(Data, 0xC0FE + GBO))
return false; // Small Fail
if (SaveUtil.ccitt16(Data.Skip(0xc100 + SBO).Take(0x121CC).ToArray()) != BitConverter.ToUInt16(Data, 0x1E2DE + SBO))
return false; // Large Fail
break;
case GameVersion.Pt:
// 0x0000-0xCF18 @ 0xCF2A
// 0xCF2C-0x1F0FC @ 0x1F10E
if (SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xCF18).ToArray()) != BitConverter.ToUInt16(Data, 0xCF2A + GBO))
return false; // Small Fail
if (SaveUtil.ccitt16(Data.Skip(0xCF2C + SBO).Take(0x121D0).ToArray()) != BitConverter.ToUInt16(Data, 0x1F10E + SBO))
return false; // Large Fail
break;
case GameVersion.HGSS:
// 0x0000-0xF618 @ 0xF626
// 0xF700-0x219FC @ 0x21A0E
if (SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xF618).ToArray()) != BitConverter.ToUInt16(Data, 0xF626 + GBO))
return false; // Small Fail
if (SaveUtil.ccitt16(Data.Skip(0xF700 + SBO).Take(0x12300).ToArray()) != BitConverter.ToUInt16(Data, 0x21A0E + SBO))
return false; // Large Fail
break;
}
return true;
}
}
public override string ChecksumInfo
{
get
{
string r = "";
switch (Version)
{
case GameVersion.DP:
// 0x0000-0xC0EC @ 0xC0FE
// 0xc100-0x1E2CC @ 0x1E2DE
if (SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xC0EC).ToArray()) != BitConverter.ToUInt16(Data, 0xC0FE + GBO))
r += "Small block checksum is invalid" + Environment.NewLine;
if (SaveUtil.ccitt16(Data.Skip(0xc100 + SBO).Take(0x121CC).ToArray()) != BitConverter.ToUInt16(Data, 0x1E2DE + SBO))
r += "Large block checksum is invalid" + Environment.NewLine;
break;
case GameVersion.Pt:
// 0x0000-0xCF18 @ 0xCF2A
// 0xCF2C-0x1F0FC @ 0x1F10E
if (SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xCF18).ToArray()) != BitConverter.ToUInt16(Data, 0xCF2A + GBO))
r += "Small block checksum is invalid" + Environment.NewLine;
if (SaveUtil.ccitt16(Data.Skip(0xCF2C + SBO).Take(0x121D0).ToArray()) != BitConverter.ToUInt16(Data, 0x1F10E + SBO))
r += "Large block checksum is invalid" + Environment.NewLine;
break;
case GameVersion.HGSS:
// 0x0000-0xF618 @ 0xF626
// 0xF700-0x219FC @ 0x21A0E
if (SaveUtil.ccitt16(Data.Skip(0 + GBO).Take(0xF618).ToArray()) != BitConverter.ToUInt16(Data, 0xF626 + GBO))
r += "Small block checksum is invalid" + Environment.NewLine;
if (SaveUtil.ccitt16(Data.Skip(0xF700 + SBO).Take(0x12300).ToArray()) != BitConverter.ToUInt16(Data, 0x21A0E + SBO))
r += "Large block checksum is invalid" + Environment.NewLine;
break;
}
return r.Length == 0 ? "Checksums valid." : r.TrimEnd();
}
}
// Blocks & Offsets
private int generalBlock = -1; // Small Block
private int storageBlock = -1; // Big Block
private int hofBlock = -1; // Hall of Fame Block
private int SBO => 0x40000 * storageBlock;
private int GBO => 0x40000 * generalBlock;
private int HBO => 0x40000 * hofBlock;
private void getActiveBlock()
{
if (Version < 0)
return;
int ofs = 0;
if (Version == GameVersion.DP) ofs = 0xC0F0; // DP
else if (Version == GameVersion.Pt) ofs = 0xCF1C; // PT
else if (Version == GameVersion.HGSS) ofs = 0xF626; // HGSS
generalBlock = BitConverter.ToUInt16(Data, ofs) >= BitConverter.ToUInt16(Data, ofs + 0x40000) ? 0 : 1;
if (Version == GameVersion.DP) ofs = 0x1E2D0; // DP
else if (Version == GameVersion.Pt) ofs = 0x1F100; // PT
else if (Version == GameVersion.HGSS) ofs = 0x21A00; // HGSS
storageBlock = BitConverter.ToUInt16(Data, ofs) >= BitConverter.ToUInt16(Data, ofs + 0x40000) ? 0 : 1;
}
private void getSAVOffsets()
{
if (Version < 0)
return;
switch (Version)
{
case GameVersion.DP:
AdventureInfo = 0 + GBO;
Trainer1 = 0x64 + GBO;
Party = 0x98 + GBO;
WondercardFlags = 0xA6D0 + GBO;
WondercardData = 0xA7fC + GBO;
OFS_PouchHeldItem = 0x624 + GBO;
OFS_PouchKeyItem = 0x8B8 + GBO;
OFS_PouchTMHM = 0x980 + GBO;
OFS_PouchMedicine = 0xB40 + GBO;
OFS_PouchBerry = 0xBE0 + GBO;
OFS_PouchBalls = 0xCE0 + GBO;
OFS_BattleItems = 0xD1C + GBO;
OFS_MailItems = 0xD50 + GBO;
LegalItems = Legal.Pouch_Items_DP;
LegalKeyItems = Legal.Pouch_Key_DP;
LegalTMHMs = Legal.Pouch_TMHM_DP;
LegalMedicine = Legal.Pouch_Medicine_DP;
LegalBerries = Legal.Pouch_Berries_DP;
LegalBalls = Legal.Pouch_Ball_DP;
LegalBattleItems = Legal.Pouch_Battle_DP;
LegalMailItems = Legal.Pouch_Mail_DP;
HeldItems = Legal.HeldItems_DP;
Daycare = 0x141C + GBO;
Box = 0xC104 + SBO;
break;
case GameVersion.Pt:
AdventureInfo = 0 + GBO;
Trainer1 = 0x68 + GBO;
Party = 0xA0 + GBO;
WondercardFlags = 0xB4C0 + GBO;
WondercardData = 0xB5C0 + GBO;
OFS_PouchHeldItem = 0x630 + GBO;
OFS_PouchKeyItem = 0x8C4 + GBO;
OFS_PouchTMHM = 0x98C + GBO;
OFS_MailItems = 0xB1C + GBO;
OFS_PouchMedicine = 0xB4C + GBO;
OFS_PouchBerry = 0xBEC + GBO;
OFS_PouchBalls = 0xCEC + GBO;
OFS_BattleItems = 0xD28 + GBO;
LegalItems = Legal.Pouch_Items_Pt;
LegalKeyItems = Legal.Pouch_Key_Pt;
LegalTMHMs = Legal.Pouch_TMHM_Pt;
LegalMedicine = Legal.Pouch_Medicine_Pt;
LegalBerries = Legal.Pouch_Berries_Pt;
LegalBalls = Legal.Pouch_Ball_Pt;
LegalBattleItems = Legal.Pouch_Battle_Pt;
LegalMailItems = Legal.Pouch_Mail_Pt;
HeldItems = Legal.HeldItems_Pt;
Daycare = 0x1654 + GBO;
Box = 0xCF30 + SBO;
break;
case GameVersion.HGSS:
AdventureInfo = 0 + GBO;
Trainer1 = 0x64 + GBO;
Party = 0x98 + GBO;
WondercardFlags = 0x9D3C + GBO;
WondercardData = 0x9E3C + GBO;
OFS_PouchHeldItem = 0x644 + GBO; // 0x644-0x8D7 (0x8CB)
OFS_PouchKeyItem = 0x8D8 + GBO; // 0x8D8-0x99F (0x979)
OFS_PouchTMHM = 0x9A0 + GBO; // 0x9A0-0xB33 (0xB2F)
OFS_MailItems = 0xB34 + GBO; // 0xB34-0xB63 (0xB63)
OFS_PouchMedicine = 0xB64 + GBO; // 0xB64-0xC03 (0xBFB)
OFS_PouchBerry = 0xC04 + GBO; // 0xC04-0xD03
OFS_PouchBalls = 0xD04 + GBO; // 0xD04-0xD63
OFS_BattleItems = 0xD64 + GBO; // 0xD64-0xD97
LegalItems = Legal.Pouch_Items_HGSS;
LegalKeyItems = Legal.Pouch_Key_HGSS;
LegalTMHMs = Legal.Pouch_TMHM_HGSS;
LegalMedicine = Legal.Pouch_Medicine_HGSS;
LegalBerries = Legal.Pouch_Berries_HGSS;
LegalBalls = Legal.Pouch_Ball_HGSS;
LegalBattleItems = Legal.Pouch_Battle_HGSS;
LegalMailItems = Legal.Pouch_Mail_HGSS;
HeldItems = Legal.HeldItems_HGSS;
Daycare = 0x15FC + GBO;
Box = 0xF700 + SBO;
break;
}
}
private int WondercardFlags = int.MinValue;
private int AdventureInfo = int.MinValue;
// Inventory
private ushort[] LegalItems, LegalKeyItems, LegalTMHMs, LegalMedicine, LegalBerries, LegalBalls, LegalBattleItems, LegalMailItems;
public override InventoryPouch[] Inventory
{
get
{
InventoryPouch[] pouch =
{
new InventoryPouch(InventoryType.Items, LegalItems, 995, OFS_PouchHeldItem),
new InventoryPouch(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem),
new InventoryPouch(InventoryType.TMHMs, LegalTMHMs, 95, OFS_PouchTMHM),
new InventoryPouch(InventoryType.Medicine, LegalMedicine, 995, OFS_PouchMedicine),
new InventoryPouch(InventoryType.Berries, LegalBerries, 995, OFS_PouchBerry),
new InventoryPouch(InventoryType.Balls, LegalBalls, 995, OFS_PouchBalls),
new InventoryPouch(InventoryType.BattleItems, LegalBattleItems, 995, OFS_BattleItems),
new InventoryPouch(InventoryType.MailItems, LegalMailItems, 995, OFS_MailItems),
};
foreach (var p in pouch)
p.getPouch(ref Data);
return pouch;
}
set
{
foreach (var p in value)
p.setPouch(ref Data);
}
}
// Storage
public override int PartyCount
{
get { return Data[Party - 4]; }
protected set { Data[Party - 4] = (byte)value; }
}
public override int getBoxOffset(int box)
{
return Box + SIZE_STORED*box*30 + (Version == GameVersion.HGSS ? box * 0x10 : 0);
}
public override int getPartyOffset(int slot)
{
return Party + SIZE_PARTY*slot;
}
// Trainer Info
public override string OT
{
get
{
return PKX.array2strG4(Data.Skip(Trainer1).Take(0x10).ToArray())
.Replace("\uE08F", "\u2640") // Nidoran ♂
.Replace("\uE08E", "\u2642") // Nidoran ♀
.Replace("\u2019", "\u0027"); // Farfetch'd
}
set
{
if (value.Length > 7)
value = value.Substring(0, 7); // Hard cap
string TempNick = value // Replace Special Characters and add Terminator
.Replace("\u2640", "\uE08F") // Nidoran ♂
.Replace("\u2642", "\uE08E") // Nidoran ♀
.Replace("\u0027", "\u2019"); // Farfetch'd
PKX.str2arrayG4(TempNick).CopyTo(Data, Trainer1);
}
}
public override ushort TID
{
get { return BitConverter.ToUInt16(Data, Trainer1 + 0x10 + 0); }
set { BitConverter.GetBytes(value).CopyTo(Data, Trainer1 + 0x10 + 0); }
}
public override ushort SID
{
get { return BitConverter.ToUInt16(Data, Trainer1 + 0x12); }
set { BitConverter.GetBytes(value).CopyTo(Data, Trainer1 + 0x12); }
}
public override uint Money
{
get { return BitConverter.ToUInt32(Data, Trainer1 + 0x14); }
set { BitConverter.GetBytes(value).CopyTo(Data, Trainer1 + 0x14); }
}
public override int Gender
{
get { return Data[Trainer1 + 0x18]; }
set { Data[Trainer1 + 0x18] = (byte)value; }
}
public override int Language
{
get { return Data[Trainer1 + 0x19]; }
set { Data[Trainer1 + 0x19] = (byte)value; }
}
public int Badges
{
get { return Data[Trainer1 + 0x1A]; }
set { if (value < 0) return; Data[Trainer1 + 0x1A] = (byte)value; }
}
public int Sprite
{
get { return Data[Trainer1 + 0x1B]; }
set { if (value < 0) return; Data[Trainer1 + 0x1B] = (byte)value; }
}
public int Badges16
{
get
{
if (Version != GameVersion.HGSS)
return -1;
return Data[Trainer1 + 0x1F];
}
set
{
if (value < 0)
return;
if (Version != GameVersion.HGSS)
return;
Data[Trainer1 + 0x1F] = (byte)value;
}
}
public override int PlayedHours
{
get { return BitConverter.ToUInt16(Data, Trainer1 + 0x22); }
set { BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0x22); }
}
public override int PlayedMinutes
{
get { return Data[Trainer1 + 0x24]; }
set { Data[Trainer1 + 0x24] = (byte)value; }
}
public override int PlayedSeconds
{
get { return Data[Trainer1 + 0x25]; }
set { Data[Trainer1 + 0x25] = (byte)value; }
}
public int M
{
get
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP:
case GameVersion.HGSS: ofs = 0x1234; break;
case GameVersion.Pt: ofs = 0x1280; break;
}
return BitConverter.ToInt32(Data, ofs);
}
set
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP:
case GameVersion.HGSS: ofs = 0x1234; break;
case GameVersion.Pt: ofs = 0x1280; break;
}
BitConverter.GetBytes(value).CopyTo(Data, ofs);
}
}
public int X
{
get
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP: ofs = 0x25FA; break;
case GameVersion.Pt: ofs = 0x287E; break;
case GameVersion.HGSS: ofs = 0x236E; break;
}
return BitConverter.ToInt32(Data, ofs);
}
set
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP: ofs = 0x25FA; break;
case GameVersion.Pt: ofs = 0x287E; break;
case GameVersion.HGSS: ofs = 0x236E; break;
}
BitConverter.GetBytes(value).CopyTo(Data, ofs);
switch (Version)
{
case GameVersion.DP:
case GameVersion.HGSS:
BitConverter.GetBytes(value).CopyTo(Data, 0x123C);
break;
}
}
}
public int Z
{
get
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP: ofs = 0x2602; break;
case GameVersion.Pt: ofs = 0x2886; break;
case GameVersion.HGSS: ofs = 0x2376; break;
}
return BitConverter.ToInt32(Data, ofs);
}
set
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP: ofs = 0x2602; break;
case GameVersion.Pt: ofs = 0x2886; break;
case GameVersion.HGSS: ofs = 0x2376; break;
}
BitConverter.GetBytes(value).CopyTo(Data, ofs);
}
}
public int Y
{
get
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP: ofs = 0x25FE; break;
case GameVersion.Pt: ofs = 0x2882; break;
case GameVersion.HGSS: ofs = 0x2372; break;
}
return BitConverter.ToInt32(Data, ofs);
}
set
{
int ofs = 0;
switch (Version)
{
case GameVersion.DP: ofs = 0x25FE; break;
case GameVersion.Pt: ofs = 0x2882; break;
case GameVersion.HGSS: ofs = 0x2372; break;
}
BitConverter.GetBytes(value).CopyTo(Data, ofs);
switch (Version)
{
case GameVersion.DP:
case GameVersion.HGSS:
BitConverter.GetBytes(value).CopyTo(Data, 0x1240);
break;
}
}
}
public override int SecondsToStart { get { return BitConverter.ToInt32(Data, AdventureInfo + 0x34); } set { BitConverter.GetBytes(value).CopyTo(Data, AdventureInfo + 0x34); } }
public override int SecondsToFame { get { return BitConverter.ToInt32(Data, AdventureInfo + 0x3C); } set { BitConverter.GetBytes(value).CopyTo(Data, AdventureInfo + 0x3C); } }
// Storage
public override int CurrentBox
{
get { return Data[Box - 4]; }
set { Data[Box - 4] = (byte)value; }
}
public override int getBoxWallpaper(int box)
{
// Box Wallpaper is directly after the Box Names
int offset = getBoxOffset(BoxCount);
if (Version == GameVersion.HGSS) offset += 0x18;
offset += BoxCount*0x28;
return Data[offset];
}
public override string getBoxName(int box)
{
int offset = getBoxOffset(BoxCount);
if (Version == GameVersion.HGSS) offset += 0x8;
return PKX.array2strG4(Data.Skip(offset + box*0x28).Take(0x28).ToArray());
}
public override void setBoxName(int box, string value)
{
if (value.Length > 13)
value = value.Substring(0, 13); // Hard cap
int offset = getBoxOffset(BoxCount);
if (Version == GameVersion.HGSS) offset += 0x8;
PKX.str2arrayG4(value).CopyTo(Data, offset + box*0x28);
}
public override PKM getPKM(byte[] data)
{
return new PK4(data);
}
public override byte[] decryptPKM(byte[] data)
{
return PKX.decryptArray45(data);
}
// Daycare
public override int getDaycareSlotOffset(int loc, int slot)
{
return Daycare + slot * SIZE_PARTY;
}
public override ulong? getDaycareRNGSeed(int loc)
{
return null;
}
public override uint? getDaycareEXP(int loc, int slot)
{
int ofs = Daycare + (slot+1)*SIZE_PARTY - 4;
return BitConverter.ToUInt32(Data, ofs);
}
public override bool? getDaycareOccupied(int loc, int slot)
{
return null;
}
public override void setDaycareEXP(int loc, int slot, uint EXP)
{
int ofs = Daycare + (slot+1)*SIZE_PARTY - 4;
BitConverter.GetBytes(EXP).CopyTo(Data, ofs);
}
public override void setDaycareOccupied(int loc, int slot, bool occupied)
{
}
// Mystery Gift
public override MysteryGiftAlbum GiftAlbum
{
get
{
return new MysteryGiftAlbum
{
Flags = MysteryGiftReceivedFlags,
Gifts = MysteryGiftCards,
};
}
set
{
MysteryGiftReceivedFlags = value.Flags;
MysteryGiftCards = value.Gifts;
}
}
protected override bool[] MysteryGiftReceivedFlags
{
get
{
if (WondercardData < 0 || WondercardFlags < 0)
return null;
bool[] r = new bool[GiftFlagMax];
for (int i = 0; i < r.Length; i++)
r[i] = (Data[WondercardFlags + (i >> 3)] >> (i & 7) & 0x1) == 1;
return r;
}
set
{
if (WondercardData < 0 || WondercardFlags < 0)
return;
if (GiftFlagMax != value?.Length)
return;
byte[] data = new byte[value.Length / 8];
for (int i = 0; i < value.Length; i++)
if (value[i])
data[i >> 3] |= (byte)(1 << (i & 7));
data.CopyTo(Data, WondercardFlags);
Edited = true;
}
}
protected override MysteryGift[] MysteryGiftCards
{
get
{
MysteryGift[] cards = new MysteryGift[8 + 3];
for (int i = 0; i < 8; i++) // 8 PGT
cards[i] = new PGT(Data.Skip(WondercardData + i * PGT.Size).Take(PGT.Size).ToArray());
for (int i = 8; i < 11; i++) // 3 PCD
cards[i] = new PCD(Data.Skip(WondercardData + 8 * PGT.Size+ (i-8) * PCD.Size).Take(PCD.Size).ToArray());
return cards;
}
set
{
if (value == null)
return;
for (int i = 0; i < 8; i++) // 8 PGT
{
if (value[i].GetType() != typeof(PGT))
continue;
value[i].Data.CopyTo(Data, WondercardData + i * PGT.Size);
}
for (int i = 8; i < 11; i++) // 3 PCD
{
if (value[i].GetType() != typeof(PCD))
continue;
value[i].Data.CopyTo(Data, WondercardData + 8 * PGT.Size + (i-8) * PGT.Size);
}
}
}
}
}