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; }
+ }
+}