diff --git a/library/Library.csproj b/library/Library.csproj index 53f8c276..191eb6c5 100644 --- a/library/Library.csproj +++ b/library/Library.csproj @@ -103,6 +103,7 @@ + diff --git a/library/Pokedex/Location.cs b/library/Pokedex/Location.cs index 87bc1799..a7b4108d 100644 --- a/library/Pokedex/Location.cs +++ b/library/Pokedex/Location.cs @@ -69,22 +69,75 @@ namespace PkmnFoundations.Pokedex public int? Value6 { get; private set; } public int? Value(Generations generation) + { + LocationNumbering numbering = GenerationToLocationNumbering(generation); + return Value(numbering); + } + + public int ? Value(LocationNumbering numbering) + { + switch (numbering) + { + case LocationNumbering.Generation1: + case LocationNumbering.Generation2: + throw new NotSupportedException(); + case LocationNumbering.Generation3: + return Value3; + case LocationNumbering.Colosseum: + return ValueColo; + case LocationNumbering.XD: + return ValueXd; + case LocationNumbering.Generation4: + return Value4; + case LocationNumbering.Generation5: + return Value5; + case LocationNumbering.Generation6: + return Value6; + default: + throw new ArgumentException(); + } + } + + public static LocationNumbering GenerationToLocationNumbering(Generations generation) { switch (generation) { case Generations.Generation1: + return LocationNumbering.Generation1; case Generations.Generation2: - throw new NotSupportedException(); + return LocationNumbering.Generation2; case Generations.Generation3: - return Value3; + return LocationNumbering.Generation3; case Generations.Generation4: - return Value4; + return LocationNumbering.Generation4; case Generations.Generation5: - return Value5; + return LocationNumbering.Generation5; case Generations.Generation6: + return LocationNumbering.Generation6; default: - return Value6; + throw new ArgumentException(); } } + + public static LazyKeyValuePair CreatePair(Pokedex pokedex) + { + return new LazyKeyValuePair( + k => k == 0 ? null : (pokedex == null ? null : pokedex.Locations(k)), + v => v == null ? 0 : v.ID); + } + + public static LazyKeyValuePair CreatePairForGeneration(Pokedex pokedex, Func generationGetter) + { + return new LazyKeyValuePair( + k => k == 0 ? null : (pokedex == null ? null : pokedex.Locations(GenerationToLocationNumbering(generationGetter()))[k]), + v => v == null ? 0 : (v.Value(generationGetter()) ?? -1)); + } + + public static LazyKeyValuePair CreatePairForLocationNumbering(Pokedex pokedex, Func generationGetter) + { + return new LazyKeyValuePair( + k => k == 0 ? null : (pokedex == null ? null : pokedex.Locations(generationGetter())[k]), + v => v == null ? 0 : (v.Value(generationGetter()) ?? -1)); + } } } diff --git a/library/Structures/Enums.cs b/library/Structures/Enums.cs index 3e778668..73a96f84 100644 --- a/library/Structures/Enums.cs +++ b/library/Structures/Enums.cs @@ -28,13 +28,14 @@ namespace PkmnFoundations.Structures public enum LocationNumbering { - Generation2 = 1, - Generation3 = 2, - Colosseum = 3, - XD = 4, - Generation4 = 5, - Generation5 = 6, - Generation6 = 7, + Generation1, + Generation2, + Generation3, + Colosseum, + XD, + Generation4, + Generation5, + Generation6 } public enum Versions : byte diff --git a/library/Structures/Pokemon4.cs b/library/Structures/Pokemon4.cs index 12d250ca..d4f79023 100644 --- a/library/Structures/Pokemon4.cs +++ b/library/Structures/Pokemon4.cs @@ -264,6 +264,42 @@ namespace PkmnFoundations.Structures public ushort LocationID_Plat { get; set; } public byte EncounterLevel { get; set; } + public override TrainerMemo TrainerMemo + { + get + { + // fixme: Pal Park memos are just saying Pal Park. We should be able to get the region too. + ushort eggLocationId, locationId; + bool plat = IsPlatHgss(); + eggLocationId = (plat && EggLocationID_Plat != 0) ? EggLocationID_Plat : EggLocationID; + locationId = (plat && LocationID_Plat != 0) ? LocationID_Plat : LocationID; + + return new TrainerMemo(m_pokedex, LocationNumbering.Generation4, + TrainerMemoDateTime(EggDate), TrainerMemoDateTime(Date), + eggLocationId, locationId, EncounterLevel == 0, EncounterLevel); + } + set + { + base.TrainerMemo = value; + } + } + + 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 @@ -308,6 +344,11 @@ namespace PkmnFoundations.Structures } } + private bool IsPlatHgss() + { + return (Version == Versions.Platinum || Version == Versions.HeartGold || Version == Versions.SoulSilver); + } + private bool IsHgss() { return (Version == Versions.HeartGold || Version == Versions.SoulSilver); diff --git a/library/Structures/PokemonPartyBase.cs b/library/Structures/PokemonPartyBase.cs index ab72307c..80d2cfa3 100644 --- a/library/Structures/PokemonPartyBase.cs +++ b/library/Structures/PokemonPartyBase.cs @@ -144,5 +144,11 @@ namespace PkmnFoundations.Structures byte mask = (byte)(1 << (value & 0x07)); return (ribbons[offset] & mask) != 0; } + + public virtual TrainerMemo TrainerMemo + { + get; + set; + } } } diff --git a/library/Structures/TrainerMemo.cs b/library/Structures/TrainerMemo.cs new file mode 100644 index 00000000..5694ab8c --- /dev/null +++ b/library/Structures/TrainerMemo.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using PkmnFoundations.Pokedex; +using PkmnFoundations.Support; + +namespace PkmnFoundations.Structures +{ + public class TrainerMemo + { + public TrainerMemo(Pokedex.Pokedex pokedex, LocationNumbering numbering, + DateTime ? time_egg_obtained, DateTime ? time_encountered, + int location_egg_obtained_id, int location_encountered_id, + bool is_hatched, byte level_encountered) + { + m_pokedex = pokedex; + m_location_egg_obtained_pair = Location.CreatePairForLocationNumbering(m_pokedex, () => Numbering); + m_location_encountered_pair = Location.CreatePairForLocationNumbering(m_pokedex, () => Numbering); + + Numbering = numbering; + TimeEggObtained = time_egg_obtained; + TimeEncountered = time_encountered; + m_location_egg_obtained_pair.Key = location_egg_obtained_id; + m_location_encountered_pair.Key = location_encountered_id; + IsHatched = is_hatched; + LevelEncountered = level_encountered; + } + + private Pokedex.Pokedex m_pokedex; + public LocationNumbering Numbering { get; private set; } + + public DateTime? TimeEggObtained { get; private set; } + public DateTime? TimeEncountered { get; private set; } + + private LazyKeyValuePair m_location_egg_obtained_pair; + public int LocationEggObtainedID + { + get + { + return m_location_egg_obtained_pair.Key; + } + } + public Location LocationEggObtained + { + get + { + return m_location_egg_obtained_pair.Value; + } + } + + private LazyKeyValuePair m_location_encountered_pair; + public int LocationEncounteredID + { + get + { + return m_location_encountered_pair.Key; + } + } + public Location LocationEncountered + { + get + { + return m_location_encountered_pair.Value; + } + } + + public bool IsHatched { get; private set; } + public byte LevelEncountered { get; private set; } + + public override String ToString() + { + if (IsHatched) + { + String timeEgg = TimeEggObtained == null ? "???" : ((DateTime)TimeEggObtained).ToString("D"); + String timeGiven = TimeEncountered == null ? "???" : ((DateTime)TimeEncountered).ToString("D"); + return String.Format("Egg obtained from {1} on {0:D}. Hatched in {3} on {2:D}.", timeEgg, LocationToString(LocationEggObtained, LocationEggObtainedID), timeGiven, LocationToString(LocationEncountered, LocationEncounteredID)); + } + else + { + String level = LevelEncountered.ToString(); + String time = TimeEncountered == null ? "???" : ((DateTime)TimeEncountered).ToString("D"); + return String.Format("Met at Lv. {0} in {2} on {1:D}.", level, time, LocationToString(LocationEncountered, LocationEncounteredID)); + } + } + + private String LocationToString(Location l, int id) + { + if (l == null || l.Name == null) return "Mystery zone #" + id.ToString(); + return l.Name.ToString(); + } + } +} diff --git a/web/gts/Pokemon.aspx.cs b/web/gts/Pokemon.aspx.cs index 13cf68c9..f9ecab56 100644 --- a/web/gts/Pokemon.aspx.cs +++ b/web/gts/Pokemon.aspx.cs @@ -92,6 +92,7 @@ namespace PkmnFoundations.Web.gts imgPokeball.ToolTip = pkmn.Pokeball.Name.ToString(); litLevel.Text = pkmn.Level.ToString(); litGender.Text = WebFormat.Gender(pkmn.Gender); + litTrainerMemo.Text = pkmn.TrainerMemo.ToString(); litCharacteristic.Text = pkmn.Characteristic.ToString(); litSpecies.Text = pkmn.Species.Name.ToString(); litPokedex.Text = pkmn.SpeciesID.ToString("000");