mirror of
https://github.com/kwsch/PKHeX
synced 2024-09-20 14:21:59 +00:00
Extract Characteristic calc to static class
Reused logic, easier unit testing, better performance. Old method would do max of 6 properties (that each fetch 32bits and bitshift themselves); now we just fetch once and shift calc accordingly.
This commit is contained in:
parent
e3d8d167be
commit
fa8e65f9e5
15 changed files with 94 additions and 122 deletions
|
@ -133,7 +133,7 @@ public sealed class BK4 : G4PKM
|
|||
public override int Move2_PPUps { get => Data[0x35]; set => Data[0x35] = (byte)value; }
|
||||
public override int Move3_PPUps { get => Data[0x36]; set => Data[0x36] = (byte)value; }
|
||||
public override int Move4_PPUps { get => Data[0x37]; set => Data[0x37] = (byte)value; }
|
||||
private uint IV32 { get => ReadUInt32BigEndian(Data.AsSpan(0x38)); set => WriteUInt32BigEndian(Data.AsSpan(0x38), value); }
|
||||
protected internal override uint IV32 { get => ReadUInt32BigEndian(Data.AsSpan(0x38)); set => WriteUInt32BigEndian(Data.AsSpan(0x38), value); }
|
||||
public override int IV_SPD { get => (int)(IV32 >> 02) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 02)) | ((value > 31 ? 31u : (uint)value) << 02); }
|
||||
public override int IV_SPA { get => (int)(IV32 >> 07) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 07)) | ((value > 31 ? 31u : (uint)value) << 07); }
|
||||
public override int IV_SPE { get => (int)(IV32 >> 12) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 12)) | ((value > 31 ? 31u : (uint)value) << 12); }
|
||||
|
@ -284,6 +284,8 @@ public sealed class BK4 : G4PKM
|
|||
public override int Stat_SPA { get; set; }
|
||||
public override int Stat_SPD { get; set; }
|
||||
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristicInvertFields(PID, IV32);
|
||||
|
||||
// Methods
|
||||
protected override ushort CalculateChecksum()
|
||||
{
|
||||
|
|
76
PKHeX.Core/PKM/EntityCharacteristic.cs
Normal file
76
PKHeX.Core/PKM/EntityCharacteristic.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public static class EntityCharacteristic
|
||||
{
|
||||
public static int GetCharacteristic(uint ec, uint iv32)
|
||||
{
|
||||
int index = (int)(ec % 6);
|
||||
|
||||
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 (maxStatIndex * 5) + ((int)maxStatValue % 5);
|
||||
}
|
||||
|
||||
public static int GetCharacteristic(uint ec, Span<int> ivs)
|
||||
{
|
||||
int index = (int)(ec % 6);
|
||||
|
||||
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 (maxStatIndex * 5) + (maxStatValue % 5);
|
||||
}
|
||||
|
||||
public static int GetCharacteristicInvertFields(uint ec, uint iv32)
|
||||
{
|
||||
int index = (int)(ec % 6);
|
||||
|
||||
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 (maxStatIndex * 5) + ((int)maxStatValue % 5);
|
||||
}
|
||||
}
|
|
@ -188,23 +188,7 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
|
||||
public override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 4;
|
||||
public override uint TSV => (uint)(TID16 ^ SID16) >> 4;
|
||||
|
||||
public override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(EncryptionConstant % 6);
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(EncryptionConstant, stackalloc int[] {IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD});
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -83,22 +83,7 @@ public sealed class PA8 : PKM, ISanityChecksum,
|
|||
public override bool IsUntraded => Data[0xB8] == 0 && Data[0xB8 + 1] == 0 && Format == Generation; // immediately terminated HT_Name data (\0)
|
||||
|
||||
// Complex Generated Attributes
|
||||
public override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(EncryptionConstant % 6);
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(EncryptionConstant, IV32);
|
||||
|
||||
// Methods
|
||||
protected override byte[] Encrypt()
|
||||
|
|
|
@ -203,7 +203,7 @@ public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, IComb
|
|||
|
||||
// 0x72 Unused
|
||||
// 0x73 Unused
|
||||
private uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x74)); set => WriteUInt32LittleEndian(Data.AsSpan(0x74), value); }
|
||||
protected override uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x74)); set => WriteUInt32LittleEndian(Data.AsSpan(0x74), value); }
|
||||
public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); }
|
||||
public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); }
|
||||
public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); }
|
||||
|
|
|
@ -131,7 +131,7 @@ public sealed class PK3 : G3PKM, ISanityChecksum
|
|||
public override int Ball { get => (Origins >> 11) & 0xF; set => Origins = (ushort)((Origins & ~0x7800) | ((value & 0xF) << 11)); }
|
||||
public override int OT_Gender { get => (Origins >> 15) & 1; set => Origins = (ushort)((Origins & ~(1 << 15)) | ((value & 1) << 15)); }
|
||||
|
||||
public uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x48)); set => WriteUInt32LittleEndian(Data.AsSpan(0x48), value); }
|
||||
private uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x48)); set => WriteUInt32LittleEndian(Data.AsSpan(0x48), value); }
|
||||
public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); }
|
||||
public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); }
|
||||
public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); }
|
||||
|
|
|
@ -113,7 +113,7 @@ public sealed class PK4 : G4PKM
|
|||
public override int Move2_PPUps { get => Data[0x35]; set => Data[0x35] = (byte)value; }
|
||||
public override int Move3_PPUps { get => Data[0x36]; set => Data[0x36] = (byte)value; }
|
||||
public override int Move4_PPUps { get => Data[0x37]; set => Data[0x37] = (byte)value; }
|
||||
public uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x38)); set => WriteUInt32LittleEndian(Data.AsSpan(0x38), value); }
|
||||
protected internal override uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x38)); set => WriteUInt32LittleEndian(Data.AsSpan(0x38), value); }
|
||||
public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); }
|
||||
public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); }
|
||||
public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); }
|
||||
|
|
|
@ -275,23 +275,7 @@ public sealed class PK5 : PKM, ISanityChecksum,
|
|||
// Generated Attributes
|
||||
public override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 3;
|
||||
public override uint TSV => (uint)(TID16 ^ SID16) >> 3;
|
||||
|
||||
public override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(PID % 6); // PID
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(PID, IV32);
|
||||
|
||||
// Maximums
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_5;
|
||||
|
|
|
@ -290,7 +290,7 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
public bool SecretSuperTrainingUnlocked { get => (Data[0x72] & 1) == 1; set => Data[0x72] = (byte)((Data[0x72] & ~1) | (value ? 1 : 0)); }
|
||||
public bool SecretSuperTrainingComplete { get => (Data[0x72] & 2) == 2; set => Data[0x72] = (byte)((Data[0x72] & ~2) | (value ? 2 : 0)); }
|
||||
// 0x73 Unused
|
||||
private uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x74)); set => WriteUInt32LittleEndian(Data.AsSpan(0x74), value); }
|
||||
protected override uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x74)); set => WriteUInt32LittleEndian(Data.AsSpan(0x74), value); }
|
||||
public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); }
|
||||
public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); }
|
||||
public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); }
|
||||
|
|
|
@ -314,7 +314,7 @@ public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
public bool SecretSuperTrainingUnlocked { get => (Data[0x72] & 1) == 1; set => Data[0x72] = (byte)((Data[0x72] & ~1) | (value ? 1 : 0)); }
|
||||
public bool SecretSuperTrainingComplete { get => (Data[0x72] & 2) == 2; set => Data[0x72] = (byte)((Data[0x72] & ~2) | (value ? 2 : 0)); }
|
||||
// 0x73 Unused
|
||||
private uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x74)); set => WriteUInt32LittleEndian(Data.AsSpan(0x74), value); }
|
||||
protected override uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x74)); set => WriteUInt32LittleEndian(Data.AsSpan(0x74), value); }
|
||||
public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); }
|
||||
public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); }
|
||||
public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); }
|
||||
|
|
|
@ -86,22 +86,7 @@ public sealed class PK9 : PKM, ISanityChecksum, ITeraType, ITechRecord, IObedien
|
|||
public bool IsUnhatchedEgg => Version == 0 && IsEgg;
|
||||
|
||||
// Complex Generated Attributes
|
||||
public override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(EncryptionConstant % 6);
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(EncryptionConstant, IV32);
|
||||
|
||||
// Methods
|
||||
protected override byte[] Encrypt()
|
||||
|
|
|
@ -116,7 +116,7 @@ public sealed class RK4 : G4PKM
|
|||
public override int Move2_PPUps { get => Data[0x35]; set => Data[0x35] = (byte)value; }
|
||||
public override int Move3_PPUps { get => Data[0x36]; set => Data[0x36] = (byte)value; }
|
||||
public override int Move4_PPUps { get => Data[0x37]; set => Data[0x37] = (byte)value; }
|
||||
public uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x38)); set => WriteUInt32LittleEndian(Data.AsSpan(0x38), value); }
|
||||
protected internal override uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x38)); set => WriteUInt32LittleEndian(Data.AsSpan(0x38), value); }
|
||||
public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); }
|
||||
public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); }
|
||||
public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); }
|
||||
|
|
|
@ -25,23 +25,8 @@ public abstract class G4PKM : PKM,
|
|||
public sealed override uint TSV => (uint)(TID16 ^ SID16) >> 3;
|
||||
|
||||
protected bool PtHGSS => Pt || HGSS;
|
||||
|
||||
public sealed override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(EncryptionConstant % 6); // PID
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
protected internal abstract uint IV32 { get; set; }
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(PID, IV32);
|
||||
|
||||
public abstract ushort Sanity { get; set; }
|
||||
public abstract ushort Checksum { get; set; }
|
||||
|
|
|
@ -48,22 +48,8 @@ public abstract class G6PKM : PKM, ISanityChecksum
|
|||
public sealed override bool IsUntraded => Data[0x78] == 0 && Data[0x78 + 1] == 0 && Format == Generation; // immediately terminated HT_Name data (\0)
|
||||
|
||||
// Complex Generated Attributes
|
||||
public sealed override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(EncryptionConstant % 6);
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
protected abstract uint IV32 { get; set; }
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(EncryptionConstant, IV32);
|
||||
|
||||
// Methods
|
||||
protected sealed override byte[] Encrypt()
|
||||
|
|
|
@ -59,22 +59,7 @@ public abstract class G8PKM : PKM, ISanityChecksum,
|
|||
public override bool IsUntraded => Data[0xA8] == 0 && Data[0xA8 + 1] == 0 && Format == Generation; // immediately terminated HT_Name data (\0)
|
||||
|
||||
// Complex Generated Attributes
|
||||
public override int Characteristic
|
||||
{
|
||||
get
|
||||
{
|
||||
int pm6 = (int)(EncryptionConstant % 6);
|
||||
int maxIV = MaximumIV;
|
||||
int pm6stat = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pm6stat = (pm6 + i) % 6;
|
||||
if (GetIV(pm6stat) == maxIV)
|
||||
break;
|
||||
}
|
||||
return (pm6stat * 5) + (maxIV % 5);
|
||||
}
|
||||
}
|
||||
public override int Characteristic => EntityCharacteristic.GetCharacteristic(EncryptionConstant, IV32);
|
||||
|
||||
// Methods
|
||||
protected override byte[] Encrypt()
|
||||
|
|
Loading…
Reference in a new issue