using System;
namespace PKHeX.Core;
///
/// Logic for calculating the characteristic behavior of Pokémon.
///
public static class EntityCharacteristic
{
///
/// Gets the characteristic index from the input parameters.
///
/// Index of the highest IV.
/// Value of the highest IV.
/// Characteristic index.
public static int GetCharacteristic(int maxStatIndex, int maxStatValue) => (maxStatIndex * 5) + (maxStatValue % 5);
///
/// Gets the characteristic index of the given IVs in Little Endian format.
///
/// Encryption Constant.
/// Lumped IVs in Little Endian format.
/// Characteristic index.
public static int GetCharacteristic(uint ec, uint iv32)
{
int index = (int)(ec % 6);
// Get individual IVs from the lumped value.
// The IVs are stored in the following order: HP, Atk, Def, Spe, SpA, SpD
// Check all IVs, get the highest IV and its index. If there are multiple highest IVs, the first index checked is chosen.
int maxStatIndex = index;
var maxStatValue = 0u;
do
{
var value = iv32 >> (index * 5) & 0x1F;
if (value > maxStatValue)
{
maxStatIndex = index;
maxStatValue = value;
}
if (index != 5)
index++;
else
index = 0;
} while (maxStatIndex != index);
return GetCharacteristic(maxStatIndex, (int)maxStatValue);
}
///
/// Gets the characteristic index of the given unpacked IVs.
///
/// Encryption Constant.
/// Unpacked IVs.
/// Characteristic index.
public static int GetCharacteristic(uint ec, Span ivs)
{
int index = (int)(ec % 6);
// Get individual IVs from the lumped value.
// The IVs are stored in the following order: HP, Atk, Def, Spe, SpA, SpD
// Check all IVs, get the highest IV and its index. If there are multiple highest IVs, the first index checked is chosen.
int maxStatIndex = index;
var maxStatValue = 0;
do
{
var value = ivs[index];
if (value > maxStatValue)
{
maxStatIndex = index;
maxStatValue = value;
}
if (index != 5)
index++;
else
index = 0;
} while (maxStatIndex != index);
return GetCharacteristic(maxStatIndex, maxStatValue);
}
///
/// Gets the characteristic index of the given IVs in Big Endian format.
///
/// Encryption Constant.
/// Lumped IVs in Big Endian format.
/// Characteristic index.
public static int GetCharacteristicInvertFields(uint ec, uint iv32)
{
int index = (int)(ec % 6);
// Get individual IVs from the lumped value.
// The IVs are stored in the following order: SpD, SpA, Spe, Def, Atk, HP
// Check all IVs, get the highest IV and its index. If there are multiple highest IVs, the first index checked is chosen.
int maxStatIndex = index;
var maxStatValue = 0u;
do
{
// IVs are stored in reverse order, get the bits from the end of the IV value
var value = iv32 >> (27 - (index * 5)) & 0x1F;
if (value > maxStatValue)
{
maxStatIndex = index;
maxStatValue = value;
}
if (index != 5)
index++;
else
index = 0;
} while (maxStatIndex != index);
return GetCharacteristic(maxStatIndex, (int)maxStatValue);
}
}