mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-23 12:33:06 +00:00
1174e354b1
* Heavily rewrites the `PKH` abstractions. * Uses HOME's core-side classes as the transfer middlemen instead of direct A->B transfers. * Revises logic to account for most of HOME's quirks (scale/height copying, safe refuge PLA) Future revisions hinge on better handling of evotree (need better metadata about existing as specific evolutions in each game). --------- Co-authored-by: sora10pls <17801814+sora10pls@users.noreply.github.com> Co-authored-by: Lusamine <30205550+Lusamine@users.noreply.github.com>
132 lines
5.8 KiB
C#
132 lines
5.8 KiB
C#
using System;
|
|
using static System.Buffers.Binary.BinaryPrimitives;
|
|
|
|
namespace PKHeX.Core;
|
|
|
|
/// <summary>
|
|
/// Side game data for <see cref="PB8"/> data transferred into HOME.
|
|
/// </summary>
|
|
public sealed class GameDataPB8 : HomeOptional1, IGameDataSide<PB8>, IGameDataSplitAbility, IPokerusStatus
|
|
{
|
|
private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PB8;
|
|
private const int SIZE = HomeCrypto.SIZE_2GAME_PB8;
|
|
protected override HomeGameDataFormat Format => ExpectFormat;
|
|
|
|
public GameDataPB8() : base(SIZE) { }
|
|
public GameDataPB8(Memory<byte> data) : base(data) => EnsureSize(SIZE);
|
|
public GameDataPB8 Clone() => new(ToArray());
|
|
public int WriteTo(Span<byte> result) => WriteWithHeader(result);
|
|
|
|
#region Structure
|
|
|
|
public ushort Move1 { get => ReadUInt16LittleEndian(Data); set => WriteUInt16LittleEndian(Data, value); }
|
|
public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x02..]); set => WriteUInt16LittleEndian(Data[0x02..], value); }
|
|
public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x04..]); set => WriteUInt16LittleEndian(Data[0x04..], value); }
|
|
public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x06..]); set => WriteUInt16LittleEndian(Data[0x06..], value); }
|
|
|
|
public int Move1_PP { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
|
public int Move2_PP { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
|
public int Move3_PP { get => Data[0x0A]; set => Data[0x0A] = (byte)value; }
|
|
public int Move4_PP { get => Data[0x0B]; set => Data[0x0B] = (byte)value; }
|
|
public int Move1_PPUps { get => Data[0x0C]; set => Data[0x0C] = (byte)value; }
|
|
public int Move2_PPUps { get => Data[0x0D]; set => Data[0x0D] = (byte)value; }
|
|
public int Move3_PPUps { get => Data[0x0E]; set => Data[0x0E] = (byte)value; }
|
|
public int Move4_PPUps { get => Data[0x0F]; set => Data[0x0F] = (byte)value; }
|
|
|
|
public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x10..]); set => WriteUInt16LittleEndian(Data[0x10..], value); }
|
|
public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x12..]); set => WriteUInt16LittleEndian(Data[0x12..], value); }
|
|
public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x14..]); set => WriteUInt16LittleEndian(Data[0x14..], value); }
|
|
public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x16..]); set => WriteUInt16LittleEndian(Data[0x16..], value); }
|
|
|
|
private Span<byte> RecordFlag => Data.Slice(0x18, 14);
|
|
public bool GetMoveRecordFlag(int index) => FlagUtil.GetFlag(RecordFlag, index >> 3, index & 7);
|
|
public void SetMoveRecordFlag(int index, bool value) => FlagUtil.SetFlag(RecordFlag, index >> 3, index & 7, value);
|
|
public bool GetMoveRecordFlagAny() => RecordFlag.IndexOfAnyExcept<byte>(0) >= 0;
|
|
public void ClearMoveRecordFlags() => RecordFlag.Clear();
|
|
|
|
public int Ball { get => Data[0x26]; set => Data[0x26] = (byte)value; }
|
|
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x27..]); set => WriteUInt16LittleEndian(Data[0x27..], (ushort)value); }
|
|
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x29..]); set => WriteUInt16LittleEndian(Data[0x29..], (ushort)value); }
|
|
|
|
// Rev2 Additions
|
|
public byte PKRS { get => Data[0x2B]; set => Data[0x2B] = value; }
|
|
public ushort Ability { get => ReadUInt16LittleEndian(Data[0x2C..]); set => WriteUInt16LittleEndian(Data[0x2C..], value); }
|
|
public byte AbilityNumber { get => Data[0x2E]; set => Data[0x2E] = value; }
|
|
|
|
#endregion
|
|
|
|
#region Conversion
|
|
|
|
public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.BDSP.GetFormEntry(species, form);
|
|
|
|
public void CopyTo(PB8 pk, PKH pkh)
|
|
{
|
|
this.CopyTo(pk);
|
|
// Move Records are not settable in PB8; do not copy even if nonzero (illegal).
|
|
pk.PKRS = PKRS;
|
|
pk.AbilityNumber = AbilityNumber;
|
|
pk.Ability = Ability;
|
|
}
|
|
|
|
public void CopyFrom(PB8 pk, PKH pkh)
|
|
{
|
|
this.CopyFrom(pk);
|
|
// Move Records are not settable in PB8; do not copy even if nonzero (illegal).
|
|
PKRS = pk.PKRS;
|
|
AbilityNumber = (byte)pk.AbilityNumber;
|
|
Ability = (ushort)pk.Ability;
|
|
}
|
|
|
|
public PB8 ConvertToPKM(PKH pkh)
|
|
{
|
|
var pk = new PB8();
|
|
pkh.CopyTo(pk);
|
|
CopyTo(pk, pkh);
|
|
|
|
pk.ResetPartyStats();
|
|
pk.RefreshChecksum();
|
|
return pk;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary> Reconstructive logic to best apply suggested values. </summary>
|
|
public static GameDataPB8? TryCreate(PKH pkh)
|
|
{
|
|
var side = GetNearestNeighbor(pkh);
|
|
if (side == null)
|
|
return null;
|
|
|
|
var result = new GameDataPB8();
|
|
result.InitializeFrom(side, pkh);
|
|
return result;
|
|
}
|
|
|
|
private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK9 as IGameDataSide
|
|
?? pkh.DataPK8 as IGameDataSide
|
|
?? pkh.DataPB7 as IGameDataSide
|
|
?? pkh.DataPA8;
|
|
|
|
public void InitializeFrom(IGameDataSide side, PKH pkh)
|
|
{
|
|
Ball = side.Ball;
|
|
Met_Location = side.Met_Location == 0 ? Locations.Default8bNone : side.Met_Location;
|
|
Egg_Location = side.Egg_Location == 0 ? Locations.Default8bNone : side.Egg_Location;
|
|
|
|
if (side is IPokerusStatus p)
|
|
PKRS = p.PKRS;
|
|
if (side is IGameDataSplitAbility a)
|
|
AbilityNumber = a.AbilityNumber;
|
|
else
|
|
AbilityNumber = 1;
|
|
|
|
PopulateFromCore(pkh);
|
|
this.ResetMoves(pkh.Species, pkh.Form, pkh.CurrentLevel, LearnSource8BDSP.Instance, EntityContext.Gen8b);
|
|
}
|
|
|
|
private void PopulateFromCore(PKH pkh)
|
|
{
|
|
var pi = PersonalTable.BDSP.GetFormEntry(pkh.Species, pkh.Form);
|
|
Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1);
|
|
}
|
|
}
|