Set height/weight dex values

Closes #2167
Based off sub_71001D16A0 with shortcut modifications:
* code marks new entries for evolution processing later using the low
bit (hence the << 1); in save files I can't see any bits set, but I
can't see anywhere in the code that DOESNT set this bit. Thus the
assumption of post-processing.

As noted in gameplay, a new capture doesn't set Min and Max; it only
sets it if it is above the usual sizing values.

Megas apparently don't set until seen in battle, so don't worry about
setting the other forme based indexes.
This commit is contained in:
Kurt 2018-11-27 22:05:36 -08:00
parent 15b6ef0597
commit 35a85670b3
3 changed files with 132 additions and 18 deletions

View File

@ -232,5 +232,40 @@ public List<EvoCriteria> GetValidPreEvolutions(PKM pkm, int maxLevel, int maxSpe
maxSpeciesOrigin = Legal.GetMaxSpeciesOrigin(pkm);
return Lineage[index].GetExplicitLineage(pkm, maxLevel, skipChecks, MaxSpeciesTree, maxSpeciesOrigin, minLevel);
}
public IEnumerable<int> 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<int> 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<int> 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;
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -1,3 +1,5 @@
using System;
namespace PKHeX.Core
{
/// <summary>
@ -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)