diff --git a/VeekunImport/Program.cs b/VeekunImport/Program.cs index 9d63e501..6b5e69a6 100644 --- a/VeekunImport/Program.cs +++ b/VeekunImport/Program.cs @@ -252,18 +252,18 @@ namespace VeekunImport int[] fieldsInt = fields.Select(s => Convert.ToInt32(s)).ToArray(); FormStats f = new FormStats(null, fieldsInt[0], (Generations)generation, fieldsInt[1], fieldsInt[2], - new StatValues(fieldsInt[3], + new IntStatValues(fieldsInt[3], fieldsInt[4], fieldsInt[5], fieldsInt[6], fieldsInt[7], fieldsInt[8]), - new StatValues(fieldsInt[9], - fieldsInt[10], - fieldsInt[11], - fieldsInt[12], - fieldsInt[13], - fieldsInt[14]) + new ByteStatValues((byte)fieldsInt[9], + (byte)fieldsInt[10], + (byte)fieldsInt[11], + (byte)fieldsInt[12], + (byte)fieldsInt[13], + (byte)fieldsInt[14]) ); db.PokedexInsertFormStats(f); diff --git a/library/Library.csproj b/library/Library.csproj index b84e536f..70a031f8 100644 --- a/library/Library.csproj +++ b/library/Library.csproj @@ -76,12 +76,20 @@ + + + + + + + + diff --git a/library/Pokedex/FormStats.cs b/library/Pokedex/FormStats.cs index e68bead1..8f7945ef 100644 --- a/library/Pokedex/FormStats.cs +++ b/library/Pokedex/FormStats.cs @@ -11,7 +11,7 @@ namespace PkmnFoundations.Pokedex public class FormStats : PokedexRecordBase { public FormStats(Pokedex pokedex, int form_id, Generations min_generation, - int type1, int type2, StatValues base_stats, StatValues reward_evs) + int type1, int type2, IntStatValues base_stats, ByteStatValues reward_evs) : base(pokedex) { m_form_pair = new LazyKeyValuePair(k => k == 0 ? null : m_pokedex.Forms(k), v => v.Value); @@ -36,7 +36,7 @@ namespace PkmnFoundations.Pokedex (Generations)Convert.ToInt32(reader["MinGeneration"]), Convert.ToInt32(reader["Type1"]), Convert.ToInt32(reader["Type2"]), - new StatValues( + new IntStatValues( Convert.ToInt32(reader["BaseHP"]), Convert.ToInt32(reader["BaseAttack"]), Convert.ToInt32(reader["BaseDefense"]), @@ -44,21 +44,21 @@ namespace PkmnFoundations.Pokedex Convert.ToInt32(reader["BaseSpAttack"]), Convert.ToInt32(reader["BaseSpDefense"]) ), - new StatValues( - Convert.ToInt32(reader["RewardHP"]), - Convert.ToInt32(reader["RewardAttack"]), - Convert.ToInt32(reader["RewardDefense"]), - Convert.ToInt32(reader["RewardSpeed"]), - Convert.ToInt32(reader["RewardSpAttack"]), - Convert.ToInt32(reader["RewardSpDefense"]) + new ByteStatValues( + Convert.ToByte(reader["RewardHP"]), + Convert.ToByte(reader["RewardAttack"]), + Convert.ToByte(reader["RewardDefense"]), + Convert.ToByte(reader["RewardSpeed"]), + Convert.ToByte(reader["RewardSpAttack"]), + Convert.ToByte(reader["RewardSpDefense"]) ) ) { } public Generations MinGeneration { get; private set; } - public StatValues BaseStats { get; private set; } - public StatValues RewardEvs { get; private set; } + public IntStatValues BaseStats { get; private set; } + public ByteStatValues RewardEvs { get; private set; } private LazyKeyValuePair m_form_pair; private LazyKeyValuePair m_type1_pair; diff --git a/library/Structures/BattleSubwayPokemon5.cs b/library/Structures/BattleSubwayPokemon5.cs index 5223114a..c4997b33 100644 --- a/library/Structures/BattleSubwayPokemon5.cs +++ b/library/Structures/BattleSubwayPokemon5.cs @@ -30,7 +30,7 @@ namespace PkmnFoundations.Structures public uint Personality; public uint IVs; public byte[] EVs; - public byte Unknown1; + public byte Unknown1; // probably a bitmask of applied PP ups public Languages Language; public byte Ability; public byte Happiness; diff --git a/library/Structures/BattleTowerPokemon4.cs b/library/Structures/BattleTowerPokemon4.cs index 0dc59ddf..712c5e37 100644 --- a/library/Structures/BattleTowerPokemon4.cs +++ b/library/Structures/BattleTowerPokemon4.cs @@ -55,7 +55,7 @@ namespace PkmnFoundations.Structures public uint Personality; public uint IVs; public byte[] EVs; - public byte Unknown1; + public byte Unknown1; // probably a bitmask of applied PP ups public Languages Language; public byte Ability; public byte Happiness; diff --git a/library/Structures/BinarySerializableBase.cs b/library/Structures/BinarySerializableBase.cs index 857ade67..93c0b017 100644 --- a/library/Structures/BinarySerializableBase.cs +++ b/library/Structures/BinarySerializableBase.cs @@ -12,6 +12,8 @@ namespace PkmnFoundations.Structures /// public abstract class BinarySerializableBase : ISerializable { + // xxx: ISerializable may be useless or even non-idiomatic on this class. + public BinarySerializableBase() { } diff --git a/library/Structures/ByteStatValues.cs b/library/Structures/ByteStatValues.cs new file mode 100644 index 00000000..29064495 --- /dev/null +++ b/library/Structures/ByteStatValues.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public class ByteStatValues : StatValues + { + public ByteStatValues(byte hp, byte attack, byte defense, byte speed, byte special_attack, byte special_defense) + : base(hp, attack, defense, special_attack, special_attack, special_defense) + { + } + + protected ByteStatValues(byte[] s) : base(s) + { + + } + } +} diff --git a/library/Structures/ContestStatValues.cs b/library/Structures/ContestStatValues.cs new file mode 100644 index 00000000..e3040f9a --- /dev/null +++ b/library/Structures/ContestStatValues.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public class ConditionValues : StatValuesBase + { + public ConditionValues(byte cool, byte beauty, byte cute, byte smart, byte tough, byte sheen) + : base(cool, beauty, cute, smart, tough, sheen) + { + + } + + public byte Cool { get { return Stats[0]; } set { Stats[0] = value; } } + public byte Beauty { get { return Stats[1]; } set { Stats[1] = value; } } + public byte Cute { get { return Stats[2]; } set { Stats[2] = value; } } + public byte Smart { get { return Stats[3]; } set { Stats[3] = value; } } + public byte Tough { get { return Stats[4]; } set { Stats[4] = value; } } + public byte Sheen { get { return Stats[5]; } set { Stats[5] = value; } } + + public static int ConditionsIndex(Conditions condition) + { + return (int)condition - 1; + } + + public virtual byte this[Conditions stat] + { + get + { + int index = ConditionsIndex(stat); + if (index < 0 || index >= 6) throw new ArgumentException(); + return Stats[index]; + } + set + { + int index = ConditionsIndex(stat); + if (index < 0 || index >= 6) throw new ArgumentException(); + Stats[index] = value; + } + } + } +} diff --git a/library/Structures/Enums.cs b/library/Structures/Enums.cs index 1fddf235..079b0e1e 100644 --- a/library/Structures/Enums.cs +++ b/library/Structures/Enums.cs @@ -91,6 +91,16 @@ namespace PkmnFoundations.Structures SpecialDefense = 6 } + public enum Conditions + { + Cool = 1, + Beauty = 2, + Cute = 3, + Smart = 4, + Tough = 5, + Sheen = 6, + } + public enum DamageClass { None = 0, @@ -173,4 +183,13 @@ namespace PkmnFoundations.Structures UserAndAllies = 13, AllPokemon = 14 } + + public enum Natures : uint + { + Hardy = 0, Lonely = 1, Brave = 2, Adamant = 3, Naughty = 4, + Bold = 5, Docile = 6, Relaxed = 7, Impish = 8, Lax = 9, + Timid = 10, Hasty = 11, Serious = 12, Jolly = 13, Naive = 14, + Modest = 15, Mild = 16, Quiet = 17, Bashful = 18, Rash = 19, + Calm = 20, Gentle = 21, Sassy = 22, Careful = 23, Quirky = 24 + } } diff --git a/library/Structures/IntStatValues.cs b/library/Structures/IntStatValues.cs new file mode 100644 index 00000000..c62bdc18 --- /dev/null +++ b/library/Structures/IntStatValues.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public class IntStatValues : StatValues + { + public IntStatValues(int hp, int attack, int defense, int speed, int special_attack, int special_defense) + : base(hp, attack, defense, special_attack, special_attack, special_defense) + { + } + + + } +} diff --git a/library/Structures/IvStatValues.cs b/library/Structures/IvStatValues.cs new file mode 100644 index 00000000..8aed1a94 --- /dev/null +++ b/library/Structures/IvStatValues.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public class IvStatValues : ByteStatValues + { + public IvStatValues(byte hp, byte attack, byte defense, byte speed, byte special_attack, byte special_defense) + : base(hp, attack, defense, special_attack, special_attack, special_defense) + { + } + + public IvStatValues(int ivs) : base(new byte[6]) + { + for (int x = 0; x < 6; x++) + { + Stats[x] = (byte)(ivs & 31); + ivs >>= 5; + } + } + + public override byte this[Stats stat] + { + get + { + return base[stat]; + } + set + { + if (value > 31) throw new ArgumentOutOfRangeException(); + base[stat] = value; + } + } + + public int ToInt32() + { + int shift = 0; + int result = 0; + foreach (byte iv in Stats) + { + result |= iv << shift; + shift += 5; + } + return result; + } + } +} diff --git a/library/Structures/MoveSlot.cs b/library/Structures/MoveSlot.cs new file mode 100644 index 00000000..6aa96c8f --- /dev/null +++ b/library/Structures/MoveSlot.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using PkmnFoundations.Pokedex; + +namespace PkmnFoundations.Structures +{ + public struct MoveSlot + { + public MoveSlot(Pokedex.Pokedex pokedex, int moveId, byte ppUps, byte remainingPp) : this() + { + m_pokedex = pokedex; + MoveID = moveId; + PPUps = ppUps; + RemainingPP = remainingPp; + } + + private Pokedex.Pokedex m_pokedex; + + public int MoveID { get; set; } + public byte PPUps { get; set; } // todo: validate range + public byte RemainingPP { get; set; } // todo: validate range (against pokedex data and pp ups) + + // todo: should have a MoveID/Move LazyKeyValuePair. + public Move Move { get { return m_pokedex.Moves(MoveID); } } + public int PP { get { return Move.PP * (5 + PPUps) / 5; } } + } +} diff --git a/library/Structures/Pokemon4.cs b/library/Structures/Pokemon4.cs new file mode 100644 index 00000000..c2a77210 --- /dev/null +++ b/library/Structures/Pokemon4.cs @@ -0,0 +1,260 @@ +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 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; } + } + } +} diff --git a/library/Structures/PokemonBase.cs b/library/Structures/PokemonBase.cs new file mode 100644 index 00000000..7806bad7 --- /dev/null +++ b/library/Structures/PokemonBase.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public abstract class PokemonBase : BinarySerializableBase + { + public PokemonBase(Pokedex.Pokedex pokedex) + : base() + { + m_pokedex = pokedex; + } + + public PokemonBase(Pokedex.Pokedex pokedex, BinaryReader data) + : base(data) + { + m_pokedex = pokedex; + } + + public PokemonBase(Pokedex.Pokedex pokedex, byte[] data) + : base(data) + { + m_pokedex = pokedex; + } + + public PokemonBase(Pokedex.Pokedex pokedex, byte[] data, int offset) + : base(data, offset) + { + m_pokedex = pokedex; + } + + protected Pokedex.Pokedex m_pokedex; + private MoveSlot[] m_moves = new MoveSlot[4]; + + // todo: use LazyKeyValuePairs for the ID fields. + public int SpeciesID { get; set; } + public int FormID { get; set; } + public int HeldItemID { get; set; } + public MoveSlot[] Moves { get { return m_moves; } } + public uint TrainerID { get; set; } + public uint Personality { get; set; } + public Natures Nature { get { return (Natures)(Personality % 25u); } } + public byte Level { get; set; } + public byte Happiness { get; set; } + public int AbilityID { get; set; } + public Languages Language { get; set; } + public IvStatValues IVs { get; set; } + public ByteStatValues EVs { get; set; } + public abstract String Nickname { get; set; } + + protected static List BlockScramble(uint personality) + { + int x = 4; // todo: this can be an argument but YAGNI + int xFactorial = 24; + + //if (x < 0) throw new ArgumentOutOfRangeException(); + //if (x == 0) return new int[0]; + + int index; + + List remaining = Enumerable.Range(0, x).ToList(); + List result = new List(x); + + while (x > 0) + { + int xMinusOneFactorial = xFactorial / x; + + index = (int)((personality % xFactorial) / xMinusOneFactorial); + result.Add(remaining[index]); + remaining.RemoveAt(index); + + x--; + xFactorial = xMinusOneFactorial; + } + + return result; + } + + protected static List Invert(List arg) + { + // todo: this is of general utility and should go in a utility class. + int max = arg.Max(); + List result = new List(max); + + for (int x = 0; x < max; x++) + result.Add(arg.IndexOf(x)); + + return result; + } + } +} diff --git a/library/Structures/StatValues.cs b/library/Structures/StatValues.cs index c00dc5c3..54f0016e 100644 --- a/library/Structures/StatValues.cs +++ b/library/Structures/StatValues.cs @@ -5,83 +5,45 @@ using System.Text; namespace PkmnFoundations.Structures { - public struct StatValues + public class StatValues : StatValuesBase where T : struct { - public StatValues(int hp, int attack, int defense, int speed, int special_attack, int special_defense) : this() + public StatValues(T hp, T attack, T defense, T speed, T special_attack, T special_defense) + : base(hp, attack, defense, speed, special_attack, special_defense) { - Hp = hp; - Attack = attack; - Defense = defense; - Speed = speed; - SpecialAttack = special_attack; - SpecialDefense = special_defense; + } - public int Hp { get; set; } - public int Attack { get; set; } - public int Defense { get; set; } - public int Speed { get; set; } - public int SpecialAttack { get; set; } - public int SpecialDefense { get; set; } + protected StatValues(T[] s) : base(s) + { + if (s.Length != 6) throw new ArgumentException(); + } - public int this[Stats stat] + public T Hp { get { return Stats[0]; } set { Stats[0] = value; } } + public T Attack { get { return Stats[1]; } set { Stats[1] = value; } } + public T Defense { get { return Stats[2]; } set { Stats[2] = value; } } + public T Speed { get { return Stats[3]; } set { Stats[3] = value; } } + public T SpecialAttack { get { return Stats[4]; } set { Stats[4] = value; } } + public T SpecialDefense { get { return Stats[5]; } set { Stats[5] = value; } } + + public static int StatsIndex(Stats stat) + { + return (int)stat - 1; + } + + public virtual T this[Stats stat] { get { - switch (stat) - { - case Stats.Hp: - return Hp; - case Stats.Attack: - return Attack; - case Stats.Defense: - return Defense; - case Stats.Speed: - return Speed; - case Stats.SpecialAttack: - return SpecialAttack; - case Stats.SpecialDefense: - return SpecialDefense; - default: - throw new ArgumentException(); - } + int index = StatsIndex(stat); + if (index < 0 || index >= 6) throw new ArgumentException(); + return Stats[index]; } set { - switch (stat) - { - case Stats.Hp: - Hp = value; - break; - case Stats.Attack: - Attack = value; - break; - case Stats.Defense: - Defense = value; - break; - case Stats.Speed: - Speed = value; - break; - case Stats.SpecialAttack: - SpecialAttack = value; - break; - case Stats.SpecialDefense: - SpecialDefense = value; - break; - default: - throw new ArgumentException(); - } + int index = StatsIndex(stat); + if (index < 0 || index >= 6) throw new ArgumentException(); + Stats[index] = value; } } - - public int[] ToArray() - { - return new int[] { Hp, Attack, Defense, Speed, SpecialAttack, SpecialDefense }; - } - - public byte[] ToByteArray() - { - return new byte[] { (byte)Hp, (byte)Attack, (byte)Defense, (byte)Speed, (byte)SpecialAttack, (byte)SpecialDefense }; - } } } diff --git a/library/Structures/StatValuesBase.cs b/library/Structures/StatValuesBase.cs new file mode 100644 index 00000000..2539c795 --- /dev/null +++ b/library/Structures/StatValuesBase.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public abstract class StatValuesBase where T : struct + { + protected StatValuesBase(T[] s) + { + Stats = s; + } + + protected StatValuesBase(T s0, T s1, T s2, T s3, T s4, T s5) + : this(new T[6] { s0, s1, s2, s3, s4, s5 }) + { + } + + protected T[] Stats { get; private set; } + + public T[] ToArray() + { + return Stats.ToArray(); + } + } +}