pkmn-classic-framework/library/Structures/Pokemon4.cs
2015-02-06 21:17:25 -05:00

261 lines
9.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using PkmnFoundations.Support;
namespace PkmnFoundations.Structures
{
public class Pokemon4 : PokemonBase
{
public Pokemon4(Pokedex.Pokedex pokedex) : base(pokedex)
{
}
public Pokemon4(Pokedex.Pokedex pokedex, BinaryReader data) : base(pokedex, data)
{
}
public Pokemon4(Pokedex.Pokedex pokedex, byte[] data) : base(pokedex, data)
{
}
public Pokemon4(Pokedex.Pokedex pokedex, byte[] data, int offset) : base(pokedex, data, offset)
{
}
protected override void Load(BinaryReader reader)
{
// header (unencrypted)
Personality = reader.ReadUInt32();
ushort zero = reader.ReadUInt16();
ushort checksum = reader.ReadUInt16();
// read out the main payload, apply xor decryption
byte[][] blocks = new byte[4][];
int rand = (int)checksum;
for (int x = 0; x < 4; x++)
{
byte[] block = blocks[x] = reader.ReadBytes(32);
// todo: extract
for (int pos = 0; pos < 32; pos += 2)
{
rand = DecryptRNG(rand);
block[pos] ^= (byte)(rand >> 24);
block[pos + 1] ^= (byte)(rand >> 16);
}
}
// shuffle blocks to their correct order
List<int> blockSequence = Invert(BlockScramble(Personality));
AssertHelper.Equals(blockSequence.Count, 4);
{
byte[][] blocks2 = new byte[4][];
for (int x = 0; x < 4; x++)
blocks2[x] = blocks[blockSequence[x]];
blocks = blocks2;
}
int ribbons1, ribbons2, ribbons3;
{
byte[] block = blocks[0];
SpeciesID = BitConverter.ToUInt16(block, 0);
HeldItemID = BitConverter.ToUInt16(block, 2);
TrainerID = BitConverter.ToUInt32(block, 4);
Experience = BitConverter.ToInt32(block, 8);
Happiness = block[12];
AbilityID = block[13];
Markings = (Markings)block[14];
Language = (Languages)block[15];
EVs = new ByteStatValues(block[16],
block[17],
block[18],
block[19],
block[20],
block[21]);
ContestStats = new ConditionValues(block[22],
block[23],
block[24],
block[25],
block[26],
block[27]);
ribbons1 = BitConverter.ToInt32(block, 28);
}
{
byte[] block = blocks[1];
Moves[0] = new MoveSlot(m_pokedex, BitConverter.ToUInt16(block, 0), block[8], block[12]);
Moves[1] = new MoveSlot(m_pokedex, BitConverter.ToUInt16(block, 2), block[9], block[13]);
Moves[2] = new MoveSlot(m_pokedex, BitConverter.ToUInt16(block, 4), block[10], block[14]);
Moves[3] = new MoveSlot(m_pokedex, BitConverter.ToUInt16(block, 6), block[11], block[15]);
int ivs = BitConverter.ToInt32(block, 16);
IVs = new IvStatValues(ivs & 0x3fffffff);
IsEgg = (ivs & 0x40000000) != 0;
HasNickname = (ivs & 0x80000000) != 0;
ribbons2 = BitConverter.ToInt32(block, 20);
byte forme = block[24];
FatefulEncounter = (forme & 0x01) != 0;
Female = (forme & 0x02) != 0;
Genderless = (forme & 0x04) != 0;
FormID = forme >> 3;
// todo: parse this in a meaningful way.
ShinyLeaves = block[25];
Unknown1 = BitConverter.ToUInt16(block, 26);
// todo: doing trainer memos the right way is a pretty large task
// involving new database work.
TrainerMemoExtended = BitConverter.ToInt32(block, 28);
}
{
byte[] block = blocks[2];
NicknameEncoded = new EncodedString4(block, 0, 22);
Unknown2 = block[22];
Version = (Versions)block[23];
ribbons3 = BitConverter.ToInt32(block, 24);
Unknown3 = BitConverter.ToInt32(block, 28);
}
{
byte[] block = blocks[3];
TrainerNameEncoded = new EncodedString4(block, 0, 16);
// todo: parse dates
EggDate = new byte[3];
Array.Copy(block, 16, EggDate, 0, 3);
Date = new byte[3];
Array.Copy(block, 19, Date, 0, 3);
TrainerMemo = BitConverter.ToInt32(block, 22);
PokerusStatus = block[26];
PokeBallID_DP = block[27];
byte encounter_level = block[28];
EncounterLevel = (byte)(encounter_level & 0x7f);
TrainerFemale = (encounter_level & 0x80) != 0;
EncounterType = block[29];
PokeBallID = block[30];
Unknown4 = block[31];
}
// todo: split this class into separate box/party versions.
{
rand = (int)Personality;
byte[] block = reader.ReadBytes(100);
for (int pos = 0; pos < 100; pos += 2)
{
rand = DecryptRNG(rand);
block[pos] ^= (byte)(rand >> 24);
block[pos + 1] ^= (byte)(rand >> 16);
}
StatusAffliction = block[0];
Unknown5 = block[1];
Unknown6 = BitConverter.ToUInt16(block, 2);
Level = block[4];
CapsuleIndex = block[5];
HP = BitConverter.ToUInt16(block, 6);
Stats = new IntStatValues(BitConverter.ToUInt16(block, 8),
BitConverter.ToUInt16(block, 10),
BitConverter.ToUInt16(block, 12),
BitConverter.ToUInt16(block, 14),
BitConverter.ToUInt16(block, 16),
BitConverter.ToUInt16(block, 18));
Unknown7 = new byte[56];
Array.Copy(block, 20, Unknown7, 0, 56);
Seals = new byte[24];
Array.Copy(block, 76, Seals, 0, 24);
}
Ribbons1 = ribbons1;
Ribbons2 = ribbons2;
Ribbons3 = ribbons3;
}
protected override void Save(BinaryWriter writer)
{
throw new NotImplementedException();
}
public int Experience { get; set; }
public Markings Markings { get; set; }
public ConditionValues ContestStats { get; set; }
public bool IsEgg { get; set; }
public bool HasNickname { get; set; }
public bool FatefulEncounter { get; set; } // aka. obedience flag
public bool Female { get; set; } // only part of gender calculations
public bool Genderless { get; set; }
public byte ShinyLeaves { get; set; }
public ushort Unknown1 { get; set; }
public int TrainerMemoExtended { get; set; } // trainer memo for PtHGSS
public EncodedString4 NicknameEncoded { get; set; }
public override string Nickname
{
get
{
return (NicknameEncoded == null) ? null : NicknameEncoded.Text;
}
set
{
if (NicknameEncoded == null) NicknameEncoded = new EncodedString4(value, 22);
else NicknameEncoded.Text = value;
}
}
public byte Unknown2 { get; set; }
public Versions Version { get; set; }
public int Unknown3 { get; set; }
public EncodedString4 TrainerNameEncoded { get; set; }
public byte[] EggDate { get; set; }
public byte[] Date { get; set; }
public int TrainerMemo { get; set; }
public byte PokerusStatus { get; set; }
public byte PokeBallID_DP { get; set; }
public byte PokeBallID { get; set; }
public byte EncounterLevel { get; set; }
public bool TrainerFemale { get; set; }
public byte EncounterType { get; set; }
public byte Unknown4 { get; set; }
public int Ribbons1 { get; set; }
public int Ribbons2 { get; set; }
public int Ribbons3 { get; set; }
public byte StatusAffliction { get; set; }
public byte Unknown5 { get; set; }
public ushort Unknown6 { get; set; }
public byte CapsuleIndex { get; set; }
public ushort HP { get; set; }
public IntStatValues Stats { get; set; } // cached stats (only refreshes per level on gen4)
public byte[] Unknown7 { get; set; }
public byte[] Seals { get; set; }
private static int DecryptRNG(int prev)
{
return prev * 0x41c64e6d + 0x6073;
}
public override int Size
{
get { return 236; }
}
}
}