From 9ef94ad18c70c81f93da07a8154fdbcc2fe79bfe Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Tue, 5 May 2015 20:09:10 -0400 Subject: [PATCH] Did some method extractions and moved things to base class in preparation for Pokemon5. --- library/Structures/Pokemon4.cs | 73 +---------------- library/Structures/PokemonPartyBase.cs | 105 +++++++++++++++++++++---- 2 files changed, 92 insertions(+), 86 deletions(-) diff --git a/library/Structures/Pokemon4.cs b/library/Structures/Pokemon4.cs index 7a0f94af..72cf03dc 100644 --- a/library/Structures/Pokemon4.cs +++ b/library/Structures/Pokemon4.cs @@ -35,7 +35,6 @@ namespace PkmnFoundations.Structures private void Initialize() { - UnknownRibbons = new HashSet(); } protected override void Load(BinaryReader reader) @@ -47,29 +46,11 @@ namespace PkmnFoundations.Structures // 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 to method - for (int pos = 0; pos < 32; pos += 2) - { - rand = DecryptRNG(rand); - block[pos] ^= (byte)(rand >> 16); - block[pos + 1] ^= (byte)(rand >> 24); - } - } + blocks[x] = reader.ReadBytes(32); - // shuffle blocks to their correct order - List blockSequence = Invert(BlockScramble((Personality & 0x0003e000) >> 0x0d)); - AssertHelper.Equals(blockSequence.Count, 4); - { - byte[][] blocks2 = new byte[4][]; - for (int x = 0; x < 4; x++) - blocks2[x] = blocks[blockSequence[x]]; - blocks = blocks2; - } + DecryptBlocks(blocks, checksum); + ShuffleBlocks(blocks, Personality, true); IsBadEgg = ComputeChecksum(blocks) != checksum; @@ -201,23 +182,6 @@ namespace PkmnFoundations.Structures get { return Generations.Generation4; } } - private bool m_female; - private bool m_genderless; - public override Genders Gender - { - get - { - if (m_genderless) return Genders.None; - if (m_female) return Genders.Female; - return Genders.Male; - } - set - { - m_female = value == Genders.Female; - m_genderless = value == Genders.None; - } - } - public ShinyLeaves ShinyLeaves { get; set; } public ushort Unknown1 { get; set; } // appears just after a flags region storing gender, forme, shiny leaves, etc. @@ -253,7 +217,6 @@ namespace PkmnFoundations.Structures } } - // todo: Implement trainer memo structure // Dates encoding seems to be 1 byte for year, starting in 2000, // 1 byte for month (1-12), and 1 byte for day of month (1-31, depending) // EggDate is all 0s if not hatched. @@ -282,28 +245,10 @@ namespace PkmnFoundations.Structures } set { - base.TrainerMemo = value; + throw new NotImplementedException(); } } - private DateTime ? TrainerMemoDateTime(byte[] data) - { - // todo: merge with GtsRecordBase datetime helper. - if (data.Length != 3) throw new ArgumentException(); - if (data[1] == 0 && data[2] == 0 && data[0] == 0) return null; - - try - { - return new DateTime(2000 + data[0], data[1], data[2]); - } - catch (ArgumentOutOfRangeException) - { - return null; - } - } - - // this is the notorious genIV encounter type flag, not used for much besides validation - public byte EncounterType { get; set; } public byte Unknown4 { get; set; } // appears just after HGSS pokeball // todo: obtain complete list of Pokeball IDs in HGSS @@ -361,16 +306,6 @@ namespace PkmnFoundations.Structures return pokeballId > 16; } - /// - /// This allows preservation of unknown ribbon flags when saving. - /// - public HashSet UnknownRibbons { get; private set; } - - protected static int DecryptRNG(int prev) - { - return prev * 0x41c64e6d + 0x6073; - } - public override int Size { get { return 136; } diff --git a/library/Structures/PokemonPartyBase.cs b/library/Structures/PokemonPartyBase.cs index 1f0c1522..52bb6ad7 100644 --- a/library/Structures/PokemonPartyBase.cs +++ b/library/Structures/PokemonPartyBase.cs @@ -18,6 +18,7 @@ namespace PkmnFoundations.Structures private void Initialize() { Ribbons = new HashSet(); + UnknownRibbons = new HashSet(); } private int m_experience; @@ -56,6 +57,23 @@ namespace PkmnFoundations.Structures } } + protected bool m_female; + protected bool m_genderless; + public override Genders Gender + { + get + { + if (m_genderless) return Genders.None; + if (m_female) return Genders.Female; + return Genders.Male; + } + set + { + m_female = value == Genders.Female; + m_genderless = value == Genders.None; + } + } + public Markings Markings { get; set; } public ConditionValues ContestStats { get; set; } public bool IsEgg { get; set; } @@ -73,9 +91,10 @@ namespace PkmnFoundations.Structures public Versions Version { get; set; } - // todo: create database-driven TrainerMemo class - // Should expose route, region, encounter type, level, date - //public abstract TrainerMemo TrainerMemo { get; } + public virtual TrainerMemo TrainerMemo { get; set; } + + // this is the notorious genIV encounter type flag, not used for much besides validation + public byte EncounterType { get; set; } public abstract String TrainerName { get; set; } public TrainerGenders TrainerGender { get; set; } @@ -84,6 +103,11 @@ namespace PkmnFoundations.Structures public HashSet Ribbons { get; private set; } + /// + /// This allows preservation of unknown ribbon flags when saving. + /// + public HashSet UnknownRibbons { get; private set; } + private IntStatValues m_stats = null; public virtual IntStatValues Stats { @@ -138,20 +162,6 @@ namespace PkmnFoundations.Structures } } - public virtual TrainerMemo TrainerMemo - { - get; - set; - } - - public static bool HasRibbon(byte[] ribbons, int value) - { - if (value >= 96 || value < 0) throw new ArgumentOutOfRangeException(); - int offset = value >> 3; - byte mask = (byte)(1 << (value & 0x07)); - return (ribbons[offset] & mask) != 0; - } - public static ushort ComputeChecksum(byte[] data) { ushort result = 0; @@ -165,5 +175,66 @@ namespace PkmnFoundations.Structures { return (ushort)data.Sum(inner => ComputeChecksum(inner)); } + + protected static int DecryptRNG(int prev) + { + return prev * 0x41c64e6d + 0x6073; + } + + protected static void DecryptBlocks(byte[][] blocks, ushort checksum) + { + int rand = (int)checksum; + + for (int x = 0; x < 4; x++) + { + byte[] block = blocks[x]; + for (int pos = 0; pos < 32; pos += 2) + { + rand = DecryptRNG(rand); + block[pos] ^= (byte)(rand >> 16); + block[pos + 1] ^= (byte)(rand >> 24); + } + } + } + + protected static void ShuffleBlocks(byte[][] blocks, uint personality, bool unshuffle) + { + // shuffle blocks to their correct order + List blockSequence = BlockScramble((personality & 0x0003e000) >> 0x0d); + if (unshuffle) blockSequence = Invert(blockSequence); + + AssertHelper.Equals(blockSequence.Count, 4); + { + byte[][] blocks2 = new byte[4][]; + for (int x = 0; x < 4; x++) + blocks2[x] = blocks[blockSequence[x]]; + for (int x = 0; x < 4; x++) + blocks[x] = blocks2[x]; + } + } + + public static bool HasRibbon(byte[] ribbons, int value) + { + if (value >= 96 || value < 0) throw new ArgumentOutOfRangeException(); + int offset = value >> 3; + byte mask = (byte)(1 << (value & 0x07)); + return (ribbons[offset] & mask) != 0; + } + + protected static DateTime? TrainerMemoDateTime(byte[] data) + { + // todo: merge with GtsRecordBase datetime helper. + if (data.Length != 3) throw new ArgumentException(); + if (data[1] == 0 && data[2] == 0 && data[0] == 0) return null; + + try + { + return new DateTime(2000 + data[0], data[1], data[2]); + } + catch (ArgumentOutOfRangeException) + { + return null; + } + } } }