2015-10-22 00:16:44 -07:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX
|
|
|
|
|
{
|
|
|
|
|
public class BlockInfo
|
|
|
|
|
{
|
|
|
|
|
public int Offset;
|
|
|
|
|
public int Length;
|
|
|
|
|
public ushort ID;
|
|
|
|
|
public ushort Checksum;
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
public enum GameVersion
|
|
|
|
|
{
|
|
|
|
|
X = 24, Y = 25,
|
|
|
|
|
AS = 26, OR = 27,
|
|
|
|
|
Z = 28,
|
|
|
|
|
Unknown = -1,
|
|
|
|
|
}
|
2015-10-22 00:16:44 -07:00
|
|
|
|
public class SAV6 : PKX
|
|
|
|
|
{
|
2015-10-23 19:58:23 -07:00
|
|
|
|
// Global Settings
|
2015-10-23 20:10:03 -07:00
|
|
|
|
internal static bool SetUpdateDex = true;
|
2015-10-23 19:58:23 -07:00
|
|
|
|
internal static bool SetUpdatePK6 = true;
|
2015-10-22 00:16:44 -07:00
|
|
|
|
// Save Data Attributes
|
|
|
|
|
public byte[] Data;
|
|
|
|
|
public bool Exportable;
|
|
|
|
|
public SAV6(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
Exportable = !data.SequenceEqual(new byte[data.Length]);
|
|
|
|
|
Data = data;
|
|
|
|
|
|
|
|
|
|
// Load Info
|
|
|
|
|
getBlockInfo();
|
|
|
|
|
getSAVOffsets();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void getSAVOffsets()
|
|
|
|
|
{
|
|
|
|
|
if (XY)
|
|
|
|
|
{
|
|
|
|
|
Box = 0x22600;
|
|
|
|
|
TrainerCard = 0x14000;
|
|
|
|
|
Party = 0x14200;
|
|
|
|
|
BattleBox = 0x04A00;
|
|
|
|
|
Daycare = 0x1B200;
|
|
|
|
|
GTS = 0x17800;
|
|
|
|
|
Fused = 0x16000;
|
|
|
|
|
SUBE = 0x1D890;
|
|
|
|
|
Puff = 0x00000;
|
|
|
|
|
Item = 0x00400;
|
|
|
|
|
Items = new Inventory(Item, 0);
|
|
|
|
|
Trainer1 = 0x1400;
|
|
|
|
|
Trainer2 = 0x4200;
|
|
|
|
|
PCLayout = 0x4400;
|
|
|
|
|
PCBackgrounds = PCLayout + 0x41E;
|
|
|
|
|
PCFlags = PCLayout + 0x43D;
|
|
|
|
|
WondercardFlags = 0x1BC00;
|
|
|
|
|
WondercardData = WondercardFlags + 0x100;
|
|
|
|
|
BerryField = 0x1B800;
|
|
|
|
|
OPower = 0x16A00;
|
|
|
|
|
EventConst = 0x14A00;
|
|
|
|
|
EventAsh = -1;
|
|
|
|
|
EventFlag = EventConst + 0x2FC;
|
|
|
|
|
PokeDex = 0x15000;
|
|
|
|
|
PokeDexLanguageFlags = PokeDex + 0x3C8;
|
|
|
|
|
Spinda = PokeDex + 0x648;
|
|
|
|
|
EncounterCount = -1;
|
|
|
|
|
HoF = 0x19400;
|
|
|
|
|
SuperTrain = 0x1F200;
|
|
|
|
|
JPEG = 0x57200;
|
|
|
|
|
MaisonStats = 0x1B1C0;
|
|
|
|
|
PSS = 0x05000;
|
|
|
|
|
PSSStats = 0x1E400;
|
|
|
|
|
Vivillon = 0x4250;
|
|
|
|
|
BoxWallpapers = 0x481E;
|
|
|
|
|
SecretBase = -1;
|
|
|
|
|
EonTicket = -1;
|
|
|
|
|
LastViewedBox = PCLayout + 0x43F;
|
|
|
|
|
}
|
|
|
|
|
else if (ORAS)
|
|
|
|
|
{
|
|
|
|
|
Box = 0x33000; // Confirmed
|
|
|
|
|
TrainerCard = 0x14000; // Confirmed
|
|
|
|
|
Party = 0x14200; // Confirmed
|
|
|
|
|
BattleBox = 0x04A00; // Confirmed
|
|
|
|
|
Daycare = 0x1BC00; // Confirmed (thanks Rei)
|
|
|
|
|
GTS = 0x18200; // Confirmed
|
|
|
|
|
Fused = 0x16A00; // Confirmed
|
|
|
|
|
SUBE = 0x1D890; // ****not in use, not updating?****
|
|
|
|
|
Puff = 0x00000; // Confirmed
|
|
|
|
|
Item = 0x00400; // Confirmed
|
|
|
|
|
Items = new Inventory(Item, 1);
|
|
|
|
|
Trainer1 = 0x01400; // Confirmed
|
|
|
|
|
Trainer2 = 0x04200; // Confirmed
|
|
|
|
|
PCLayout = 0x04400; // Confirmed
|
|
|
|
|
PCBackgrounds = PCLayout + 0x41E;
|
|
|
|
|
PCFlags = PCLayout + 0x43D;
|
|
|
|
|
WondercardFlags = 0x1CC00; // Confirmed
|
|
|
|
|
WondercardData = WondercardFlags + 0x100;
|
|
|
|
|
BerryField = 0x1C400; // ****changed****
|
|
|
|
|
OPower = 0x17400; // ****changed****
|
|
|
|
|
EventConst = 0x14A00;
|
|
|
|
|
EventAsh = EventConst + 0x78;
|
|
|
|
|
EventFlag = EventConst + 0x2FC;
|
|
|
|
|
PokeDex = 0x15000;
|
|
|
|
|
Spinda = PokeDex + 0x680;
|
|
|
|
|
EncounterCount = PokeDex + 0x686;
|
|
|
|
|
PokeDexLanguageFlags = PokeDex + 0x400;
|
|
|
|
|
HoF = 0x19E00; // Confirmed
|
|
|
|
|
SuperTrain = 0x20200;
|
|
|
|
|
JPEG = 0x67C00; // Confirmed
|
|
|
|
|
MaisonStats = 0x1BBC0;
|
|
|
|
|
PSS = 0x05000; // Confirmed (thanks Rei)
|
|
|
|
|
PSSStats = 0x1F400;
|
|
|
|
|
Vivillon = 0x4244;
|
|
|
|
|
BoxWallpapers = 0x481E;
|
|
|
|
|
SecretBase = 0x23A00;
|
|
|
|
|
EonTicket = 0x319B8;
|
|
|
|
|
LastViewedBox = PCLayout + 0x43F;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Box = TrainerCard = Party = BattleBox = GTS = Daycare =
|
|
|
|
|
Fused = SUBE = Puff = Item = Trainer1 = Trainer2 = SecretBase = EonTicket = LastViewedBox = BoxWallpapers =
|
|
|
|
|
PCLayout = PCBackgrounds = PCFlags = WondercardFlags = WondercardData = BerryField = OPower = SuperTrain = MaisonStats = PSSStats = Vivillon =
|
|
|
|
|
EventConst = EventAsh = EventFlag = PokeDex = PokeDexLanguageFlags = Spinda = EncounterCount = HoF = PSS = JPEG = 0;
|
|
|
|
|
Items = new Inventory(Item, -1);
|
|
|
|
|
}
|
|
|
|
|
DaycareSlot = new[] { Daycare, Daycare + 0x1F0 };
|
|
|
|
|
}
|
|
|
|
|
public class Inventory
|
|
|
|
|
{
|
|
|
|
|
public int HeldItem, KeyItem, Medicine, TMHM, Berry;
|
|
|
|
|
public Inventory(int Offset, int Game)
|
|
|
|
|
{
|
|
|
|
|
switch (Game)
|
|
|
|
|
{
|
2015-10-23 19:45:25 -07:00
|
|
|
|
case 0:
|
2015-10-22 00:16:44 -07:00
|
|
|
|
HeldItem = Offset + 0;
|
|
|
|
|
KeyItem = Offset + 0x640;
|
|
|
|
|
TMHM = Offset + 0x7C0;
|
|
|
|
|
Medicine = Offset + 0x968;
|
|
|
|
|
Berry = Offset + 0xA68;
|
|
|
|
|
break;
|
2015-10-23 19:45:25 -07:00
|
|
|
|
case 1:
|
2015-10-22 00:16:44 -07:00
|
|
|
|
HeldItem = Offset + 0;
|
|
|
|
|
KeyItem = Offset + 0x640;
|
|
|
|
|
TMHM = Offset + 0x7C0;
|
|
|
|
|
Medicine = Offset + 0x970;
|
|
|
|
|
Berry = Offset + 0xA70;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
HeldItem = KeyItem = TMHM = Medicine = Berry = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public Inventory Items;
|
|
|
|
|
public int Box, Party, BattleBox, GTS, Daycare, EonTicket,
|
|
|
|
|
Fused, SUBE, Puff, Item, Trainer1, Trainer2, SuperTrain, PSSStats, MaisonStats, Vivillon, SecretBase, BoxWallpapers, LastViewedBox,
|
|
|
|
|
PCLayout, PCBackgrounds, PCFlags, WondercardFlags, WondercardData, BerryField, OPower, EventConst, EventFlag, EventAsh,
|
|
|
|
|
PokeDex, PokeDexLanguageFlags, Spinda, EncounterCount, HoF, PSS, JPEG;
|
|
|
|
|
public int TrainerCard = 0x14000;
|
|
|
|
|
public int[] DaycareSlot;
|
|
|
|
|
public int DaycareIndex = 0;
|
|
|
|
|
|
|
|
|
|
public GameVersion Version
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
switch (Game)
|
|
|
|
|
{
|
|
|
|
|
case 24: return GameVersion.X;
|
|
|
|
|
case 25: return GameVersion.Y;
|
|
|
|
|
case 26: return GameVersion.AS;
|
|
|
|
|
case 27: return GameVersion.OR;
|
|
|
|
|
}
|
|
|
|
|
return GameVersion.Unknown;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public bool ORAS { get { return ((Version == GameVersion.OR) || (Version == GameVersion.AS)); } }
|
|
|
|
|
public bool XY { get { return ((Version == GameVersion.X) || (Version == GameVersion.Y)); } }
|
|
|
|
|
|
|
|
|
|
// Save Information
|
|
|
|
|
private int BlockInfoOffset;
|
|
|
|
|
private BlockInfo[] Blocks;
|
|
|
|
|
private void getBlockInfo()
|
|
|
|
|
{
|
|
|
|
|
BlockInfoOffset = Data.Length - 0x200 + 0x10;
|
|
|
|
|
if (BitConverter.ToUInt32(Data, BlockInfoOffset) != 0x42454546) // BEEF, nice!
|
|
|
|
|
BlockInfoOffset -= 0x200; // No savegames have more than 0x3D blocks, maybe in the future?
|
|
|
|
|
int count = (Data.Length - BlockInfoOffset - 0x8) / 8;
|
|
|
|
|
BlockInfoOffset += 4;
|
|
|
|
|
|
|
|
|
|
Blocks = new BlockInfo[count];
|
|
|
|
|
int CurrentPosition = 0;
|
|
|
|
|
for (int i = 0; i < Blocks.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
Blocks[i] = new BlockInfo
|
|
|
|
|
{
|
|
|
|
|
Offset = CurrentPosition,
|
|
|
|
|
Length = BitConverter.ToInt32(Data, BlockInfoOffset + 0 + 8*i),
|
|
|
|
|
ID = BitConverter.ToUInt16(Data, BlockInfoOffset + 4 + 8*i),
|
|
|
|
|
Checksum = BitConverter.ToUInt16(Data, BlockInfoOffset + 6 + 8*i)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Expand out to nearest 0x200
|
|
|
|
|
CurrentPosition += (Blocks[i].Length % 0x200 == 0) ? Blocks[i].Length : (0x200 - Blocks[i].Length % 0x200 + Blocks[i].Length);
|
|
|
|
|
|
|
|
|
|
if ((Blocks[i].ID != 0) || i == 0) continue;
|
|
|
|
|
count = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// Fix Final Array Lengths
|
|
|
|
|
Array.Resize(ref Blocks, count);
|
|
|
|
|
}
|
|
|
|
|
private void setChecksums()
|
|
|
|
|
{
|
|
|
|
|
// Check for invalid block lengths
|
|
|
|
|
if (Blocks.Length < 3) // arbitrary...
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Not enough blocks ({0}), aborting setChecksums", Blocks.Length);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Apply checksums
|
|
|
|
|
for (int i = 0; i < Blocks.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
byte[] array = Data.Skip(Blocks[i].Offset).Take(Blocks[i].Length).ToArray();
|
|
|
|
|
Array.Copy(BitConverter.GetBytes(ccitt16(array)), 0, Data, BlockInfoOffset + 6 + i * 8, 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public byte[] Write()
|
|
|
|
|
{
|
|
|
|
|
setChecksums();
|
|
|
|
|
return Data;
|
|
|
|
|
}
|
|
|
|
|
public int CurrentBox { get { return Data[LastViewedBox] & 0x1F; } set { Data[LastViewedBox] = (byte)value; } }
|
|
|
|
|
|
|
|
|
|
// Player Information
|
|
|
|
|
public ushort TID { get { return BitConverter.ToUInt16(Data, TrainerCard + 0); } }
|
|
|
|
|
public ushort SID { get { return BitConverter.ToUInt16(Data, TrainerCard + 2); } }
|
|
|
|
|
public byte Game { get { return Data[TrainerCard + 4]; } }
|
|
|
|
|
public byte Gender { get { return Data[TrainerCard + 5]; } }
|
|
|
|
|
public byte SubRegion { get { return Data[TrainerCard + 0x26]; } }
|
|
|
|
|
public byte Country { get { return Data[TrainerCard + 0x27]; } }
|
|
|
|
|
public byte ConsoleRegion { get { return Data[TrainerCard + 0x2C]; } }
|
|
|
|
|
public byte Language { get { return Data[TrainerCard + 0x2D]; } }
|
|
|
|
|
public string OT { get { return Util.TrimFromZero(Encoding.Unicode.GetString(Data, TrainerCard + 0x48, 0x1A)); } }
|
|
|
|
|
|
|
|
|
|
// Misc Properties
|
|
|
|
|
public int PartyCount
|
|
|
|
|
{
|
|
|
|
|
get { return Data[Party + 6 * PK6.SIZE_PARTY]; }
|
|
|
|
|
set { Data[Party + 6 * PK6.SIZE_PARTY] = (byte)value; }
|
|
|
|
|
}
|
|
|
|
|
public bool BattleBoxLocked
|
|
|
|
|
{
|
|
|
|
|
get { return Data[BattleBox + 6 * PK6.SIZE_STORED] != 0; }
|
|
|
|
|
set { Data[BattleBox + 6 * PK6.SIZE_STORED] = (byte)(value ? 1 : 0); }
|
|
|
|
|
}
|
|
|
|
|
public ulong DaycareRNGSeed
|
|
|
|
|
{
|
|
|
|
|
get { return BitConverter.ToUInt64(Data, DaycareSlot[DaycareIndex] + 0x1E8); }
|
|
|
|
|
set { BitConverter.GetBytes(value).CopyTo(Data, DaycareSlot[DaycareIndex] + 0x1E8); }
|
|
|
|
|
}
|
|
|
|
|
public bool DaycareHasEgg
|
|
|
|
|
{
|
|
|
|
|
get { return Data[DaycareSlot[DaycareIndex] + 0x1E0] == 1; }
|
|
|
|
|
set { Data[DaycareSlot[DaycareIndex] + 0x1E0] = (byte)(value ? 1 : 0); }
|
|
|
|
|
}
|
|
|
|
|
public uint DaycareEXP1
|
|
|
|
|
{
|
|
|
|
|
get { return BitConverter.ToUInt32(Data, DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8)*0 + 4); }
|
|
|
|
|
set { BitConverter.GetBytes(value).CopyTo(Data, DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8)*0 + 4); }
|
|
|
|
|
}
|
|
|
|
|
public uint DaycareEXP2
|
|
|
|
|
{
|
|
|
|
|
get { return BitConverter.ToUInt32(Data, DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8)*1 + 4); }
|
|
|
|
|
set { BitConverter.GetBytes(value).CopyTo(Data, DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8)*1 + 4); }
|
|
|
|
|
}
|
|
|
|
|
public bool DaycareOccupied1
|
|
|
|
|
{
|
|
|
|
|
get { return Data[DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8)*0] != 0; }
|
|
|
|
|
set { Data[DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8)*0] = (byte) (value ? 1 : 0); }
|
|
|
|
|
}
|
|
|
|
|
public bool DaycareOccupied2
|
|
|
|
|
{
|
|
|
|
|
get { return Data[DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8) * 1] != 0; }
|
|
|
|
|
set { Data[DaycareSlot[DaycareIndex] + (PK6.SIZE_STORED + 8) * 1] = (byte)(value ? 1 : 0); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Data Accessing
|
|
|
|
|
public byte[] getData(int Offset, int Length)
|
|
|
|
|
{
|
|
|
|
|
return Data.Skip(Offset).Take(Length).ToArray();
|
|
|
|
|
}
|
|
|
|
|
public void setData(byte[] input, int Offset)
|
|
|
|
|
{
|
|
|
|
|
input.CopyTo(Data, Offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pokémon Requests
|
|
|
|
|
public PK6 getPK6Party(int offset)
|
|
|
|
|
{
|
|
|
|
|
return new PK6(decryptArray(getData(offset , PK6.SIZE_PARTY)));
|
|
|
|
|
}
|
|
|
|
|
public PK6 getPK6Stored(int offset)
|
|
|
|
|
{
|
|
|
|
|
return new PK6(decryptArray(getData(offset, PK6.SIZE_STORED)));
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
public void setPK6Party(PK6 pk6, int offset, bool? trade = null, bool? dex = null)
|
2015-10-22 00:16:44 -07:00
|
|
|
|
{
|
2015-10-23 19:58:23 -07:00
|
|
|
|
if (SetUpdatePK6 || (trade ?? false))
|
2015-10-22 00:16:44 -07:00
|
|
|
|
{
|
|
|
|
|
// Apply to this Save File
|
|
|
|
|
// pk6.Trade();
|
|
|
|
|
// pk6.Write();
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
if (SetUpdateDex || (dex ?? false))
|
2015-10-23 19:58:23 -07:00
|
|
|
|
setPokeDex(pk6);
|
|
|
|
|
|
2015-10-22 00:16:44 -07:00
|
|
|
|
byte[] ek6 = encryptArray(pk6.Data);
|
|
|
|
|
setData(ek6, offset);
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
public void setPK6Stored(PK6 pk6, int offset, bool? trade = null, bool? dex = null)
|
2015-10-22 00:16:44 -07:00
|
|
|
|
{
|
2015-10-23 19:58:23 -07:00
|
|
|
|
if (SetUpdatePK6 || (trade ?? false))
|
2015-10-22 00:16:44 -07:00
|
|
|
|
{
|
|
|
|
|
// Apply to this Save File
|
|
|
|
|
// pk6.Trade();
|
|
|
|
|
// pk6.Write();
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
if (SetUpdateDex || (dex ?? false))
|
2015-10-23 19:58:23 -07:00
|
|
|
|
setPokeDex(pk6);
|
|
|
|
|
|
2015-10-22 00:16:44 -07:00
|
|
|
|
byte[] ek6 = encryptArray(pk6.Data);
|
|
|
|
|
Array.Resize(ref ek6, PK6.SIZE_STORED);
|
|
|
|
|
setData(ek6, offset);
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
public void setEK6Stored(byte[] ek6, int offset, bool? trade = null, bool? dex = null)
|
2015-10-22 00:16:44 -07:00
|
|
|
|
{
|
|
|
|
|
PK6 pk6 = new PK6(decryptArray(ek6));
|
2015-10-23 19:58:23 -07:00
|
|
|
|
if (SetUpdatePK6 || (trade ?? false))
|
2015-10-22 00:16:44 -07:00
|
|
|
|
{
|
|
|
|
|
// Apply to this Save File
|
|
|
|
|
// pk6.Trade();
|
|
|
|
|
// pk6.Write();
|
|
|
|
|
}
|
2015-10-23 20:10:03 -07:00
|
|
|
|
if (SetUpdateDex || (dex ?? false))
|
2015-10-23 19:58:23 -07:00
|
|
|
|
setPokeDex(pk6);
|
|
|
|
|
|
2015-10-22 00:16:44 -07:00
|
|
|
|
Array.Resize(ref ek6, PK6.SIZE_STORED);
|
|
|
|
|
setData(ek6, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Meta
|
|
|
|
|
public void setPokeDex(PK6 pk6)
|
|
|
|
|
{
|
|
|
|
|
if (pk6.Species == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int bit = pk6.Species - 1;
|
|
|
|
|
int lang = pk6.Language - 1; if (lang > 5) lang--; // 0-6 language vals
|
|
|
|
|
int origin = pk6.Version;
|
2015-10-23 19:45:25 -07:00
|
|
|
|
int gender = pk6.Gender % 2; // genderless -> male
|
2015-10-22 00:16:44 -07:00
|
|
|
|
int shiny = pk6.IsShiny ? 1 : 0;
|
|
|
|
|
int shiftoff = (shiny * 0x60 * 2) + (gender * 0x60) + 0x60;
|
|
|
|
|
|
|
|
|
|
// Set the [Species/Gender/Shiny] Owned Flag
|
|
|
|
|
Data[PokeDex + shiftoff + bit / 8 + 0x8] |= (byte)(1 << (bit % 8));
|
|
|
|
|
|
|
|
|
|
// Owned quality flag
|
|
|
|
|
if (origin < 0x18 && bit < 649 && !ORAS) // Species: 1-649 for X/Y, and not for ORAS; Set the Foreign Owned Flag
|
|
|
|
|
Data[PokeDex + 0x64C + bit / 8] |= (byte)(1 << (bit % 8));
|
|
|
|
|
else if (origin >= 0x18 || ORAS) // Set Native Owned Flag (should always happen)
|
|
|
|
|
Data[PokeDex + bit / 8 + 0x8] |= (byte)(1 << (bit % 8));
|
|
|
|
|
|
|
|
|
|
// Set the Display flag if none are set
|
|
|
|
|
bool[] chk =
|
|
|
|
|
{
|
|
|
|
|
// Flag Regions (base index 1 to reference Wiki and editor)
|
|
|
|
|
(Data[PokeDex + 0x60*(5) + bit/8 + 0x8] & (byte) (1 << (bit%8))) != 0,
|
|
|
|
|
(Data[PokeDex + 0x60*(6) + bit/8 + 0x8] & (byte) (1 << (bit%8))) != 0,
|
|
|
|
|
(Data[PokeDex + 0x60*(7) + bit/8 + 0x8] & (byte) (1 << (bit%8))) != 0,
|
|
|
|
|
(Data[PokeDex + 0x60*(8) + bit/8 + 0x8] & (byte) (1 << (bit%8))) != 0,
|
|
|
|
|
};
|
|
|
|
|
if (!chk.Contains(true)) // offset is already biased by 0x60, reuse shiftoff but for the display flags.
|
|
|
|
|
Data[PokeDex + shiftoff + 0x60 * (4) + bit / 8 + 0x8] |= (byte)(1 << (bit % 8));
|
|
|
|
|
|
|
|
|
|
// Set the Language
|
|
|
|
|
if (lang < 0) lang = 1;
|
|
|
|
|
Data[PokeDex + PokeDexLanguageFlags + (bit * 7 + lang) / 8] |= (byte)(1 << (((bit * 7) + lang) % 8));
|
|
|
|
|
}
|
|
|
|
|
public int getBoxWallpaper(int box)
|
|
|
|
|
{
|
|
|
|
|
return 1 + Data[BoxWallpapers + box];
|
|
|
|
|
}
|
|
|
|
|
public void setParty()
|
|
|
|
|
{
|
|
|
|
|
byte partymembers = 0; // start off with a ctr of 0
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
{
|
|
|
|
|
// Gather all the species
|
|
|
|
|
byte[] data = new byte[PK6.SIZE_PARTY];
|
|
|
|
|
Array.Copy(Data, Party + i * PK6.SIZE_PARTY, data, 0, PK6.SIZE_PARTY);
|
|
|
|
|
byte[] decdata = decryptArray(data);
|
|
|
|
|
int species = BitConverter.ToInt16(decdata, 8);
|
|
|
|
|
if ((species != 0) && (species < 722))
|
|
|
|
|
Array.Copy(data, 0, Data, Party + (partymembers++) * PK6.SIZE_PARTY, PK6.SIZE_PARTY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write in the current party count
|
|
|
|
|
PartyCount = partymembers;
|
|
|
|
|
// Zero out the party slots that are empty.
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
if (i >= partymembers)
|
|
|
|
|
Array.Copy(encryptArray(new byte[PK6.SIZE_PARTY]), 0, Data, Party + (i * PK6.SIZE_PARTY), PK6.SIZE_PARTY);
|
|
|
|
|
|
|
|
|
|
// Repeat for Battle Box.
|
|
|
|
|
byte battlemem = 0;
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
{
|
|
|
|
|
// Gather all the species
|
|
|
|
|
byte[] data = new byte[PK6.SIZE_PARTY];
|
|
|
|
|
Array.Copy(Data, BattleBox + i * PK6.SIZE_STORED, data, 0, PK6.SIZE_STORED);
|
|
|
|
|
byte[] decdata = decryptArray(data);
|
|
|
|
|
int species = BitConverter.ToInt16(decdata, 8);
|
|
|
|
|
if ((species != 0) && (species < 722))
|
|
|
|
|
Array.Copy(data, 0, Data, BattleBox + (battlemem++) * PK6.SIZE_STORED, PK6.SIZE_STORED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Zero out the party slots that are empty.
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
if (i >= battlemem)
|
|
|
|
|
Array.Copy(encryptArray(new byte[PK6.SIZE_PARTY]), 0, Data, BattleBox + (i * PK6.SIZE_STORED), PK6.SIZE_STORED);
|
|
|
|
|
|
|
|
|
|
if (battlemem == 0)
|
|
|
|
|
BattleBoxLocked = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|