using System; using System.Collections.Generic; using System.IO; using System.Linq; using static DSPRE.RomInfo; namespace DSPRE.ROMFiles { public enum PokemonGender { Male = 0, Female = 254, Unknown = 255 } public enum PokemonType { Normal = 0, Fighting, Flying, Poison, Ground, Rock, Bug, Ghost, Steel, Unknown, Fire, Water, Grass, Electric, Psychic, Ice, Dragon, Dark } public enum PokemonGrowthCurve { MediumFast = 0, Erratic, Fluctuating, MediumSlow, Fast, Slow } public enum PokemonEggGroup { Unassigned = 0, Monster, Water1, Bug, Flying, Field, Fairy, Grass, Humanoid, Water3, Mineral, Amorphous, Water2, Ditto, Dragon, NoBreed, }; public enum PokemonDexColor { Red = 0, Blue, Yellow, Green, Black, Brown, Purple, Gray, White, Pink, Unspecified } public class PokemonPersonalData : RomFile { public static readonly int tmsCount = 92; public static readonly int hmsCount = 8; public byte baseHP; public byte baseAtk; public byte baseDef; public byte baseSpeed; public byte baseSpAtk; public byte baseSpDef; public PokemonType type1; public PokemonType type2; public byte catchRate; public byte givenExp; //Part of a u16 bitfield, 2 bits each. public byte evHP; public byte evAtk; public byte evDef; public byte evSpeed; public byte evSpAtk; public byte evSpDef; public ushort item1; // First item that the mon may hold when caught public ushort item2; // Second item that the mon may hold when caught public byte genderVec; public byte eggSteps; public byte baseFriendship; public PokemonGrowthCurve growthCurve; public byte eggGroup1; public byte eggGroup2; public byte firstAbility; public byte secondAbility; public byte escapeRate; public PokemonDexColor color;// : 7; // Color (used in Pokedex) public bool flip;// : 1; // Flip Flag public SortedSet machines; public PokemonPersonalData(Stream stream) { using (BinaryReader reader = new BinaryReader(stream)) { // Deserialize the object from binary baseHP = reader.ReadByte(); baseAtk = reader.ReadByte(); baseDef = reader.ReadByte(); baseSpeed = reader.ReadByte(); baseSpAtk = reader.ReadByte(); baseSpDef = reader.ReadByte(); type1 = (PokemonType)reader.ReadByte(); type2 = (PokemonType)reader.ReadByte(); catchRate = reader.ReadByte(); givenExp = reader.ReadByte(); ushort evData = reader.ReadUInt16(); evHP = (byte)(evData & 0b11); evAtk = (byte)((evData >> 2) & 0b11); evDef = (byte)((evData >> 4) & 0b11); evSpeed = (byte)((evData >> 6) & 0b11); evSpAtk = (byte)((evData >> 8) & 0b11); evSpDef = (byte)((evData >> 10) & 0b11); item1 = reader.ReadUInt16(); item2 = reader.ReadUInt16(); genderVec = reader.ReadByte(); eggSteps = reader.ReadByte(); baseFriendship = reader.ReadByte(); growthCurve = (PokemonGrowthCurve)reader.ReadByte(); eggGroup1 = reader.ReadByte(); eggGroup2 = reader.ReadByte(); firstAbility = reader.ReadByte(); secondAbility = reader.ReadByte(); escapeRate = reader.ReadByte(); byte colorAndFlip = reader.ReadByte(); color = (PokemonDexColor)(colorAndFlip & 0b01111111); flip = ((colorAndFlip >> 7) & 0b00000001) == 1; reader.BaseStream.Position += 2; //Alignment uint tm1 = reader.ReadUInt32(); uint tm2 = reader.ReadUInt32(); uint tm3 = reader.ReadUInt32(); uint tm4 = reader.ReadUInt32(); machines = BitFieldToSet(new uint[4] { tm1, tm2, tm3, tm4 }); } } public PokemonPersonalData(int ID) : this(new FileStream(RomInfo.gameDirs[DirNames.personalPokeData].unpackedDir + "\\" + ID.ToString("D4"), FileMode.Open)) { } public override byte[] ToByteArray() { using (MemoryStream stream = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(stream)) { // Serialize the object to binary writer.Write(baseHP); writer.Write(baseAtk); writer.Write(baseDef); writer.Write(baseSpeed); writer.Write(baseSpAtk); writer.Write(baseSpDef); writer.Write((byte)type1); writer.Write((byte)type2); writer.Write(catchRate); writer.Write(givenExp); ushort evData = (ushort)((evHP & 0b11) | ((evAtk & 0b11) << 2) | ((evDef & 0b11) << 4) | ((evSpeed & 0b11) << 6) | ((evSpAtk & 0b11) << 8) | ((evSpDef & 0b11) << 10)); writer.Write(evData); writer.Write(item1); writer.Write(item2); writer.Write(genderVec); writer.Write(eggSteps); writer.Write(baseFriendship); writer.Write((byte)growthCurve); writer.Write(eggGroup1); writer.Write(eggGroup2); writer.Write(firstAbility); writer.Write(secondAbility); writer.Write(escapeRate); byte colorAndFlipflag = (byte)(((byte)color & 0b01111111) | (((flip ? 1 : 0) & 0b00000001) << 7)); writer.Write(colorAndFlipflag); writer.BaseStream.Position += 2; //Alignment uint[] bfs = SetToBitField(machines); int l = Math.Min(bfs.Length, 4); int i; for (i = 0; i < l; i++) { writer.Write(bfs[i]); } while (i < 4) { writer.Write((uint)0); i++; } } return stream.ToArray(); } } public SortedSet BitFieldToSet(uint[] bitfield) { var result = new SortedSet(); for (uint i = 0; i < bitfield.Length; i++) { uint currentBitfield = bitfield[i]; for (int j = 0; j < 32; j++) { if ((currentBitfield & (1 << j)) != 0) { result.Add((byte)(i * 32 + j)); } } } return result; } public uint[] SetToBitField(SortedSet set) { if (set == null) { return null; } if (set.Count == 0) { return new uint[0]; } int maxBit = set.Max(); uint[] bitfield = new uint[(maxBit / 32) + 1]; foreach (byte bit in set) { int index = bit / 32; int offset = bit % 32; bitfield[index] |= (uint)(1 << offset); } return bitfield; } public void SaveToFileDefaultDir(int IDtoReplace, bool showSuccessMessage = true) { SaveToFileDefaultDir(DirNames.personalPokeData, IDtoReplace, showSuccessMessage); } public void SaveToFileExplorePath(string suggestedFileName, bool showSuccessMessage = true) { SaveToFileExplorePath("Gen IV Personal Pokémon data", "bin", suggestedFileName, showSuccessMessage); } } }