PKHeX/PKHeX.Core/PKM/Shared/G6PKM.cs
Kurt 88830e0d00
Update from .NET Framework 4.6 to .NET 7 (#3729)
Updates from net46->net7, dropping support for mono in favor of using the latest runtime (along with the performance/API improvements). Releases will be posted as 64bit only for now.

Refactors a good amount of internal API methods to be more performant and more customizable for future updates & fixes.

Adds functionality for Batch Editor commands to `>`, `<` and <=/>=

TID/SID properties renamed to TID16/SID16 for clarity; other properties exposed for Gen7 / display variants.

Main window has a new layout to account for DPI scaling (8 point grid)

Fixed: Tatsugiri and Paldean Tauros now output Showdown form names as Showdown expects
Changed: Gen9 species now interact based on the confirmed National Dex IDs (closes #3724)
Fixed: Pokedex set all no longer clears species with unavailable non-base forms (closes #3720)
Changed: Hyper Training suggestions now apply for level 50 in SV. (closes #3714)
Fixed: B2/W2 hatched egg met locations exclusive to specific versions are now explicitly checked (closes #3691)
Added: Properties for ribbon/mark count (closes #3659)
Fixed: Traded SV eggs are now checked correctly (closes #3692)
2023-01-21 20:02:33 -08:00

134 lines
4.6 KiB
C#

using System;
using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core;
/// <summary> Generation 6 <see cref="PKM"/> format. </summary>
public abstract class G6PKM : PKM, ISanityChecksum
{
public override int SIZE_PARTY => PokeCrypto.SIZE_6PARTY;
public override int SIZE_STORED => PokeCrypto.SIZE_6STORED;
protected G6PKM(byte[] data) : base(data) { }
protected G6PKM(int size) : base(size) { }
// Trash Bytes
public sealed override Span<byte> Nickname_Trash => Data.AsSpan(0x40, 26);
public sealed override Span<byte> HT_Trash => Data.AsSpan(0x78, 26);
public sealed override Span<byte> OT_Trash => Data.AsSpan(0xB0, 26);
public abstract ushort Sanity { get; set; }
public abstract ushort Checksum { get; set; }
public sealed override void RefreshChecksum() => Checksum = CalculateChecksum();
public sealed override bool ChecksumValid => CalculateChecksum() == Checksum;
public sealed override bool Valid { get => Sanity == 0 && ChecksumValid; set { if (!value) return; Sanity = 0; RefreshChecksum(); } }
private ushort CalculateChecksum()
{
ushort chk = 0;
for (int i = 8; i < PokeCrypto.SIZE_6STORED; i += 2) // don't use SIZE_STORED property; pb7 overrides stored size
chk += ReadUInt16LittleEndian(Data.AsSpan(i));
return chk;
}
// Simple Generated Attributes
public sealed override int CurrentFriendship
{
get => CurrentHandler == 0 ? OT_Friendship : HT_Friendship;
set { if (CurrentHandler == 0) OT_Friendship = value; else HT_Friendship = value; }
}
public int OppositeFriendship
{
get => CurrentHandler == 1 ? OT_Friendship : HT_Friendship;
set { if (CurrentHandler == 1) OT_Friendship = value; else HT_Friendship = value; }
}
public sealed override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 4;
public sealed override uint TSV => (uint)(TID16 ^ SID16) >> 4;
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);
}
}
// Methods
protected sealed override byte[] Encrypt()
{
RefreshChecksum();
return PokeCrypto.EncryptArray6(Data);
}
// General User-error Fixes
public void FixRelearn()
{
while (true)
{
if (RelearnMove4 != 0 && RelearnMove3 == 0)
{
RelearnMove3 = RelearnMove4;
RelearnMove4 = 0;
}
if (RelearnMove3 != 0 && RelearnMove2 == 0)
{
RelearnMove2 = RelearnMove3;
RelearnMove3 = 0;
continue;
}
if (RelearnMove2 != 0 && RelearnMove1 == 0)
{
RelearnMove1 = RelearnMove2;
RelearnMove2 = 0;
continue;
}
break;
}
}
// Synthetic Trading Logic
public void Trade(ITrainerInfo tr, int Day = 1, int Month = 1, int Year = 2015)
{
if (IsEgg)
{
// Eggs do not have any modifications done if they are traded
// Apply link trade data, only if it left the OT (ignore if dumped & imported, or cloned, etc)
if ((tr.TID16 != TID16) || (tr.SID16 != SID16) || (tr.Gender != OT_Gender) || (tr.OT != OT_Name))
SetLinkTradeEgg(Day, Month, Year, Locations.LinkTrade6);
return;
}
// Process to the HT if the OT of the Pokémon does not match the SAV's OT info.
if (!TradeOT(tr))
TradeHT(tr);
}
protected abstract bool TradeOT(ITrainerInfo tr);
protected abstract void TradeHT(ITrainerInfo tr);
// Maximums
public sealed override int MaxIV => 31;
public sealed override int MaxEV => 252;
public sealed override int MaxStringLengthOT => 12;
public sealed override int MaxStringLengthNickname => 12;
}
public interface ISuperTrain
{
uint SuperTrainBitFlags { get; set; }
bool SecretSuperTrainingUnlocked { get; set; }
bool SecretSuperTrainingComplete { get; set; }
int SuperTrainingMedalCount(int maxCount = 30);
}