diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs b/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs index 6601a84d4..1981cb866 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs @@ -232,5 +232,40 @@ public List GetValidPreEvolutions(PKM pkm, int maxLevel, int maxSpe maxSpeciesOrigin = Legal.GetMaxSpeciesOrigin(pkm); return Lineage[index].GetExplicitLineage(pkm, maxLevel, skipChecks, MaxSpeciesTree, maxSpeciesOrigin, minLevel); } + + public IEnumerable GetEvolutionsAndPreEvolutions(int species, int form) + { + foreach (var s in GetPreEvolutions(species, form)) + yield return s; + yield return species; + foreach (var s in GetEvolutions(species, form)) + yield return s; + } + + private IEnumerable GetPreEvolutions(int species, int form) + { + int index = Personal.GetFormeIndex(species, form); + var node = Lineage[index]; + foreach (var z in node.Chain) + { + foreach (var prevo in z.StageEntryMethods) + yield return prevo.Species; + } + } + + private IEnumerable GetEvolutions(int species, int form) + { + int index = Personal.GetFormeIndex(species, form); + var node = Entries[index]; + foreach (var z in node.PossibleEvolutions) + { + var s = z.Species; + if (s == 0) + continue; + yield return s; + foreach (var next in GetEvolutions(s, form)) + yield return next; + } + } } } diff --git a/PKHeX.Core/PKM/PB7.cs b/PKHeX.Core/PKM/PB7.cs index 8cdaccafc..fac80835e 100644 --- a/PKHeX.Core/PKM/PB7.cs +++ b/PKHeX.Core/PKM/PB7.cs @@ -705,17 +705,24 @@ public int AwakeCP } } + public void ResetCP() => Stat_CP = CalcCP; + + public void ResetCalculatedValues() + { + ResetCP(); + ResetHeight(); + ResetWeight(); + } + // ReSharper disable RedundantCast // Casts are as per the game code; they may seem redundant but every bit of precision matters? // This still doesn't precisely match :( -- just use a tolerance check when updating. // If anyone can figure out how to get all precision to match, feel free to update :) - public float HeightRatio => (float)((float)((float)(byte)HeightScalar / 255.0f) * 0.8f) + 0.6f; - public float WeightRatio => (float)((float)((float)((float)((float)(byte) WeightScalar / 255.0f) * 0.4f) + 0.8f)); + public float HeightRatio => GetHeightRatio(HeightScalar); + public float WeightRatio => GetWeightRatio(WeightScalar); - public float CalcHeightAbsolute => HeightRatio * (float)PersonalInfo.Height; - public float CalcWeightAbsolute => HeightRatio * (float)(WeightRatio * (float)PersonalInfo.Weight); - - public void ResetCP() => Stat_CP = CalcCP; + public float CalcHeightAbsolute => GetHeightAbsolute(PersonalInfo, HeightScalar); + public float CalcWeightAbsolute => GetWeightAbsolute(PersonalInfo, HeightScalar, WeightScalar); public void ResetHeight() { @@ -733,13 +740,6 @@ public void ResetWeight() WeightAbsolute = updated; } - public void ResetCalculatedValues() - { - ResetCP(); - ResetHeight(); - ResetWeight(); - } - public static int GetHeightRating(int heightScalar) { if (heightScalar < 0x10) @@ -752,5 +752,29 @@ public static int GetHeightRating(int heightScalar) return 3; // 2/16 = L return 4; // 1/16 = XL } + + private static float GetHeightRatio(int heightScalar) + { + return (float)((float)((float)(byte)heightScalar / 255.0f) * 0.8f) + 0.6f; + } + + private static float GetWeightRatio(int weightScalar) + { + return (float)((float)((float)((float)((float)(byte)weightScalar / 255.0f) * 0.4f) + 0.8f)); + } + + public static float GetHeightAbsolute(PersonalInfo p, int heightScalar) + { + float HeightRatio = GetHeightRatio(heightScalar); + return HeightRatio * (float)p.Height; + } + + public static float GetWeightAbsolute(PersonalInfo p, int heightScalar, int weightScalar) + { + float HeightRatio = GetHeightRatio(heightScalar); + float WeightRatio = GetWeightRatio(weightScalar); + + return HeightRatio * (float)(WeightRatio * (float)p.Weight); + } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs index d7a4d3907..5c5ae94de 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs @@ -1,3 +1,5 @@ +using System; + namespace PKHeX.Core { /// @@ -30,7 +32,7 @@ public override void SetDex(PKM pkm) { if (!TryGetIndex(pkm.AltForm, pkm.Species, out _)) return; - SetSizeData(pkm); + SetSizeData((PB7)pkm); base.SetDex(pkm); } @@ -43,16 +45,69 @@ protected override void SetDex(int species, int bit, int form, int gender, bool private static bool IsBuddy(int species, int form) => (species == 25 && form == 8) || (species == 133 && form == 1); - private void SetSizeData(PKM pkm) + private void SetSizeData(PB7 pkm) { int species = pkm.Species; int form = pkm.AltForm; if (!TryGetIndex(form, species, out int index)) return; - const int group = 0; // what differentiates the 4 groups? - int offset = 0x3978 + (index * 6) + (group * 0x45C); //0x1170/4 - // todo? + if (Math.Round(pkm.HeightAbsolute) < pkm.PersonalInfo.Height) // possible minimum height + { + int ofs = GetDexSizeOffset(0, index); + var minHeight = BitConverter.ToUInt16(SAV.Data, ofs) >> 1; + var calcHeight = PB7.GetHeightAbsolute(pkm.PersonalInfo, minHeight); + if (Math.Round(pkm.HeightAbsolute) < Math.Round(calcHeight) || BitConverter.ToUInt32(SAV.Data, ofs) == 0x007F00FE) // unset + UpdateSizeIndex(pkm, 0); + } + else if (Math.Round(pkm.HeightAbsolute) > pkm.PersonalInfo.Height) // possible maximum height + { + int ofs = GetDexSizeOffset(1, index); + var maxHeight = BitConverter.ToUInt16(SAV.Data, ofs) >> 1; + var calcHeight = PB7.GetHeightAbsolute(pkm.PersonalInfo, maxHeight); + if (Math.Round(pkm.HeightAbsolute) > Math.Round(calcHeight) || BitConverter.ToUInt32(SAV.Data, ofs) == 0x007F00FE) // unset + UpdateSizeIndex(pkm, 1); + } + + if (Math.Round(pkm.WeightAbsolute) < pkm.PersonalInfo.Weight) // possible minimum weight + { + int ofs = GetDexSizeOffset(2, index); + var minWeight = BitConverter.ToUInt16(SAV.Data, ofs + 2); + var minHeight = BitConverter.ToUInt16(SAV.Data, ofs) >> 1; + var calcWeight = PB7.GetWeightAbsolute(pkm.PersonalInfo, minHeight, minWeight); + if (Math.Round(pkm.WeightAbsolute) < Math.Round(calcWeight) || BitConverter.ToUInt32(SAV.Data, ofs) == 0x007F00FE) // unset + UpdateSizeIndex(pkm, 2); + } + else if (Math.Round(pkm.WeightAbsolute) > pkm.PersonalInfo.Weight) // possible maximum weight + { + int ofs = GetDexSizeOffset(3, index); + var maxWeight = BitConverter.ToUInt16(SAV.Data, ofs + 2); + var maxHeight = BitConverter.ToUInt16(SAV.Data, ofs) >> 1; + var calcWeight = PB7.GetWeightAbsolute(pkm.PersonalInfo, maxHeight, maxWeight); + if (Math.Round(pkm.WeightAbsolute) > Math.Round(calcWeight) || BitConverter.ToUInt32(SAV.Data, ofs) == 0x007F00FE) // unset + UpdateSizeIndex(pkm, 3); + } + } + + private int GetDexSizeOffset(int group, int index) => 0x3978 + (index * 6) + (group * 0x45C); // blockofs + 0xF78 + ([186*6]*n) + x*6 + + private void UpdateSizeIndex(PB7 pkm, int group) + { + var tree = EvolutionTree.GetEvolutionTree(pkm, 7); + int species = pkm.Species; + int form = pkm.AltForm; + + // update for all species in potential lineage + var allspec = tree.GetEvolutionsAndPreEvolutions(species, form); + foreach (var s in allspec) + { + if (!TryGetIndex(form, s, out var index)) + continue; // shouldn't hit this + + var ofs = GetDexSizeOffset(group, index); + BitConverter.GetBytes((ushort)(pkm.HeightScalar << 1)).CopyTo(SAV.Data, ofs); + BitConverter.GetBytes((ushort)(pkm.WeightScalar)).CopyTo(SAV.Data, ofs + 2); + } } private static bool TryGetIndex(int form, int species, out int index)