mirror of
https://github.com/mm201/pkmn-classic-framework.git
synced 2026-08-28 05:04:16 -05:00
Did some method extractions and moved things to base class in preparation for Pokemon5.
This commit is contained in:
@@ -35,7 +35,6 @@ namespace PkmnFoundations.Structures
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
UnknownRibbons = new HashSet<int>();
|
||||
}
|
||||
|
||||
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<int> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This allows preservation of unknown ribbon flags when saving.
|
||||
/// </summary>
|
||||
public HashSet<int> UnknownRibbons { get; private set; }
|
||||
|
||||
protected static int DecryptRNG(int prev)
|
||||
{
|
||||
return prev * 0x41c64e6d + 0x6073;
|
||||
}
|
||||
|
||||
public override int Size
|
||||
{
|
||||
get { return 136; }
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace PkmnFoundations.Structures
|
||||
private void Initialize()
|
||||
{
|
||||
Ribbons = new HashSet<Ribbon>();
|
||||
UnknownRibbons = new HashSet<int>();
|
||||
}
|
||||
|
||||
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<Ribbon> Ribbons { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This allows preservation of unknown ribbon flags when saving.
|
||||
/// </summary>
|
||||
public HashSet<int> 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<int> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user