From 35f484924ecceaa3e6c7806524bf839fc5f4e8ad Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Tue, 24 Feb 2015 13:12:12 -0500 Subject: [PATCH] Added base class for party/box pokemon structure. --- library/Library.csproj | 1 + library/Pokedex/Item.cs | 14 +++ library/Pokedex/Pokedex.cs | 8 ++ library/Structures/Pokemon4.cs | 146 +++++++++++++++++++++---- library/Structures/PokemonBase.cs | 2 + library/Structures/PokemonPartyBase.cs | 49 +++++++++ 6 files changed, 197 insertions(+), 23 deletions(-) create mode 100644 library/Structures/PokemonPartyBase.cs diff --git a/library/Library.csproj b/library/Library.csproj index 8e87e91d..62318aa6 100644 --- a/library/Library.csproj +++ b/library/Library.csproj @@ -94,6 +94,7 @@ + diff --git a/library/Pokedex/Item.cs b/library/Pokedex/Item.cs index 4507fe30..25c62282 100644 --- a/library/Pokedex/Item.cs +++ b/library/Pokedex/Item.cs @@ -66,6 +66,13 @@ namespace PkmnFoundations.Pokedex } } + public int ? PokeballValue + { + // fixme: this needs to be its own field in the database. + // (see full comment at Pokedex.Pokeballs) + get { return Value6; } + } + public static LazyKeyValuePair CreatePair(Pokedex pokedex) { return new LazyKeyValuePair( @@ -79,5 +86,12 @@ namespace PkmnFoundations.Pokedex k => k == 0 ? null : (pokedex == null ? null : pokedex.Items(generationGetter(), k)), v => v == null ? 0 : (v.Value(generationGetter()) ?? -1)); } + + public static LazyKeyValuePair CreatePairPokeball(Pokedex pokedex) + { + return new LazyKeyValuePair( + k => k == 0 ? null : (pokedex == null ? null : pokedex.Pokeballs(k)), + v => v == null ? 0 : v.ID); + } } } diff --git a/library/Pokedex/Pokedex.cs b/library/Pokedex/Pokedex.cs index 443423fd..42389a5d 100644 --- a/library/Pokedex/Pokedex.cs +++ b/library/Pokedex/Pokedex.cs @@ -165,6 +165,14 @@ namespace PkmnFoundations.Pokedex return m_items_generations[generation][value]; } + public Item Pokeballs(int value) + { + // fixme: fact check the values for apricorn pokeballs. + // What's used here is most assuredly wrong (and probably quite silly) + // todo: add a PokeballValue field to the Items table and a dictionary here + return m_items_generations[Generations.Generation6][value]; + } + public Move Moves(int value) { return m_moves[value]; diff --git a/library/Structures/Pokemon4.cs b/library/Structures/Pokemon4.cs index 235ec855..b9cb77ac 100644 --- a/library/Structures/Pokemon4.cs +++ b/library/Structures/Pokemon4.cs @@ -3,32 +3,40 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using PkmnFoundations.Pokedex; using PkmnFoundations.Support; namespace PkmnFoundations.Structures { - public class Pokemon4 : PokemonBase + public class Pokemon4 : PokemonPartyBase { public Pokemon4(Pokedex.Pokedex pokedex) : base(pokedex) { - + Initialize(); } public Pokemon4(Pokedex.Pokedex pokedex, BinaryReader data) : base(pokedex) { + Initialize(); Load(data); } public Pokemon4(Pokedex.Pokedex pokedex, byte[] data) : base(pokedex) { + Initialize(); Load(data); } public Pokemon4(Pokedex.Pokedex pokedex, byte[] data, int offset) : base(pokedex) { + Initialize(); Load(data, offset); } + private void Initialize() + { + } + protected override void Load(BinaryReader reader) { // header (unencrypted) @@ -114,11 +122,11 @@ namespace PkmnFoundations.Structures // todo: parse this in a meaningful way. ShinyLeaves = block[25]; - Unknown1 = BitConverter.ToUInt16(block, 26); + Unknown1 = BitConverter.ToUInt16(block, 26); // Probably unused? // todo: doing trainer memos the right way is a pretty large task // involving new database work. - TrainerMemoExtended = BitConverter.ToInt32(block, 28); + TrainerMemoPlatinum = BitConverter.ToInt32(block, 28); } { @@ -144,14 +152,14 @@ namespace PkmnFoundations.Structures TrainerMemo = BitConverter.ToInt32(block, 22); PokerusStatus = block[26]; - PokeBallID_DP = block[27]; + PokeBallID = block[27]; byte encounter_level = block[28]; EncounterLevel = (byte)(encounter_level & 0x7f); TrainerFemale = (encounter_level & 0x80) != 0; EncounterType = block[29]; - PokeBallID = block[30]; + PokeBallID_Hgss = block[30]; Unknown4 = block[31]; } @@ -172,7 +180,7 @@ namespace PkmnFoundations.Structures Level = block[4]; CapsuleIndex = block[5]; HP = BitConverter.ToUInt16(block, 6); - Stats = new IntStatValues(BitConverter.ToUInt16(block, 8), + m_stats = new IntStatValues(BitConverter.ToUInt16(block, 8), BitConverter.ToUInt16(block, 10), BitConverter.ToUInt16(block, 12), BitConverter.ToUInt16(block, 14), @@ -227,22 +235,29 @@ namespace PkmnFoundations.Structures get { return Generations.Generation4; } } - // todo: link experience with level - 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 - // todo: validate gender against PV - public bool Female { get; set; } // only part of gender calculations + public bool Female { get; set; } public bool Genderless { get; set; } + public override Genders Gender + { + get + { + if (Genderless) return Genders.None; + if (Female) return Genders.Female; + return Genders.Male; + } + set + { + Female = value == Genders.Female; + Genderless = value == Genders.None; + } + } + // todo: parse shiny leaves data public byte ShinyLeaves { get; set; } public ushort Unknown1 { get; set; } - // todo: parse trainer memos (location, level) + // this will require some database work. - public int TrainerMemoExtended { get; set; } // trainer memo for PtHGSS + public int TrainerMemoPlatinum { get; set; } // trainer memo for PtHGSS public EncodedString4 NicknameEncoded { get; set; } public override string Nickname { @@ -258,20 +273,96 @@ namespace PkmnFoundations.Structures } } public byte Unknown2 { get; set; } - public Versions Version { get; set; } public int Unknown3 { get; set; } public EncodedString4 TrainerNameEncoded { get; set; } + public override string TrainerName + { + get + { + return (TrainerNameEncoded == null) ? null : TrainerNameEncoded.Text; + } + set + { + if (TrainerName == value) return; + if (TrainerNameEncoded == null) TrainerNameEncoded = new EncodedString4(value, 16); + else TrainerNameEncoded.Text = value; + } + } // fixme: use DateTimes for these - public byte[] EggDate { get; set; } - public byte[] Date { get; set; } + public byte[] EggDate { get; set; } // 3 bytes + public byte[] Date { get; set; } // 3 bytes public int TrainerMemo { get; set; } + // todo: parse pokerus public byte PokerusStatus { get; set; } + // todo: need list of values and map them onto items - public byte PokeBallID_DP { get; set; } public byte PokeBallID { get; set; } + public byte PokeBallID_Hgss { get; set; } + + private Item m_pokeball; + public override Pokedex.Item Pokeball + { + get + { + if (m_pokeball != null) return m_pokeball; + int pokeballId = IsHgss() ? PokeBallID_Hgss : PokeBallID; + m_pokeball = m_pokedex.Pokeballs(pokeballId); + return m_pokeball; + } + set + { + if (m_pokeball == value) return; + if (value == null) + { + m_pokeball = null; + return; + } + + if (value.PokeballValue == null) throw new ArgumentException("Item is not a valid Pokeball."); + if ((int)value.PokeballValue > 255 || (int)value.PokeballValue < 0) + throw new ArgumentOutOfRangeException("Pokeball ID must be within the valid range for a byte."); + + int pokeballId = (int)value.PokeballValue; + bool is_hgss = IsHgss(); + bool is_hgss_pokeball = IsHgssPokeball(pokeballId); + if (!is_hgss && is_hgss_pokeball) throw new NotSupportedException("Can't place an HGSS Pokeball on a DPPt Pokémon."); + + // todo: fact check these two values: + // 1. a pokemon in an HGSS ball has a DPPt value of 1 + // 2. any pokemon from DPPt has an HGSS value of 0 + // (investigating pokemon in the system should be enough) + PokeBallID = (byte)(is_hgss_pokeball ? 1 : pokeballId); + PokeBallID_Hgss = (byte)(is_hgss ? pokeballId : 0); + } + } + + private bool IsHgss() + { + return !(Version == Versions.Diamond || + Version == Versions.Pearl || + Version == Versions.Platinum); + } + + private bool IsHgssPokeball(int pokeballId) + { + return pokeballId > 16; + } + public byte EncounterLevel { get; set; } public bool TrainerFemale { get; set; } + public override TrainerGenders TrainerGender + { + get + { + return TrainerFemale ? TrainerGenders.Female : TrainerGenders.Male; + } + set + { + TrainerFemale = value == TrainerGenders.Female; + } + } + // this is the notorious genIV encounter type flag, not used for much besides validation public byte EncounterType { get; set; } public byte Unknown4 { get; set; } @@ -280,15 +371,24 @@ namespace PkmnFoundations.Structures public int Ribbons2 { get; set; } public int Ribbons3 { get; set; } + // party-only stuff. (todo: put in derived class) public byte StatusAffliction { get; set; } + // todo: ball seals 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 IntStatValues Stats { get; set; } // cached stats (only refreshes per level on gen4) public byte[] Unknown7 { get; set; } public byte[] Seals { get; set; } + private IntStatValues m_stats; + + public override IntStatValues Stats + { + get { return m_stats; } + } + private static int DecryptRNG(int prev) { return prev * 0x41c64e6d + 0x6073; diff --git a/library/Structures/PokemonBase.cs b/library/Structures/PokemonBase.cs index 56521f74..481b644f 100644 --- a/library/Structures/PokemonBase.cs +++ b/library/Structures/PokemonBase.cs @@ -122,6 +122,8 @@ namespace PkmnFoundations.Structures public Languages Language { get; set; } public IvStatValues IVs { get; set; } public ByteStatValues EVs { get; set; } + + public abstract Genders Gender { get; set; } public abstract String Nickname { get; set; } protected static List BlockScramble(uint personality) diff --git a/library/Structures/PokemonPartyBase.cs b/library/Structures/PokemonPartyBase.cs new file mode 100644 index 00000000..b31764db --- /dev/null +++ b/library/Structures/PokemonPartyBase.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using PkmnFoundations.Pokedex; +using PkmnFoundations.Support; + +namespace PkmnFoundations.Structures +{ + public abstract class PokemonPartyBase : PokemonBase + { + public PokemonPartyBase(Pokedex.Pokedex pokedex) + : base(pokedex) + { + Initialize(); + } + + private void Initialize() + { + } + + // todo: link experience with level + 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; } // this field decides whether or not its name gets reverted when it evolves. + public bool FatefulEncounter { get; set; } // aka. obedience flag. A few pokemon, eg. Mew, are disobedient unless this is set. + 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 abstract String TrainerName { get; set; } + public abstract TrainerGenders TrainerGender { get; set; } + + // todo: Add pokerus status (None, Infected, Cured) and pokerus days remaining + //public abstract PokerusStatus PokerusStatus { get; set; } + //public abstract int PokerusDaysLeft { get; set; } + + public abstract Item Pokeball { get; set; } + + // todo: implement ribbons store (see Pokemon4.Load comment) + //public HashSet Ribbons { get; } + + public abstract IntStatValues Stats { get; } + } +}