2022-06-19 16:26:28 +00:00
using System ;
2023-01-22 04:02:33 +00:00
using System.Numerics ;
2022-01-03 05:35:59 +00:00
using static System . Buffers . Binary . BinaryPrimitives ;
2016-06-20 04:22:43 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
/// <summary> Generation 3 <see cref="PKM"/> format. </summary>
public sealed class PK3 : G3PKM , ISanityChecksum
2016-06-20 04:22:43 +00:00
{
2023-03-26 00:55:55 +00:00
public override ReadOnlySpan < ushort > ExtraBytes = > new ushort [ ]
2016-06-20 04:22:43 +00:00
{
2022-06-18 18:04:24 +00:00
0x2A , 0x2B ,
} ;
2018-09-15 05:37:47 +00:00
2022-06-18 18:04:24 +00:00
public override int SIZE_PARTY = > PokeCrypto . SIZE_3PARTY ;
public override int SIZE_STORED = > PokeCrypto . SIZE_3STORED ;
public override EntityContext Context = > EntityContext . Gen3 ;
2023-01-22 04:02:33 +00:00
public override PersonalInfo3 PersonalInfo = > PersonalTable . RS [ Species ] ;
2016-10-24 05:01:39 +00:00
2022-06-18 18:04:24 +00:00
public PK3 ( ) : base ( PokeCrypto . SIZE_3PARTY ) { }
public PK3 ( byte [ ] data ) : base ( DecryptParty ( data ) ) { }
2018-11-21 22:15:48 +00:00
2022-06-18 18:04:24 +00:00
private static byte [ ] DecryptParty ( byte [ ] data )
{
PokeCrypto . DecryptIfEncrypted3 ( ref data ) ;
Array . Resize ( ref data , PokeCrypto . SIZE_3PARTY ) ;
return data ;
}
2018-09-15 05:37:47 +00:00
2023-01-22 04:02:33 +00:00
public override PK3 Clone ( )
2022-06-18 18:04:24 +00:00
{
// Don't use the byte[] constructor, the DecryptIfEncrypted call is based on checksum.
// An invalid checksum will shuffle the data; we already know it's un-shuffled. Set up manually.
2023-01-22 04:02:33 +00:00
PK3 pk = new ( ) ;
2022-06-18 18:04:24 +00:00
Data . CopyTo ( pk . Data , 0 ) ;
return pk ;
}
2016-06-20 04:22:43 +00:00
2022-06-18 18:04:24 +00:00
private const string EggNameJapanese = "タマゴ" ;
2018-12-15 07:26:46 +00:00
2022-06-18 18:04:24 +00:00
// Trash Bytes
public override Span < byte > Nickname_Trash = > Data . AsSpan ( 0x08 , 10 ) ; // no inaccessible terminator
public override Span < byte > OT_Trash = > Data . AsSpan ( 0x14 , 7 ) ; // no inaccessible terminator
2017-04-09 21:06:50 +00:00
2022-06-18 18:04:24 +00:00
// At top for System.Reflection execution order hack
2016-06-20 04:22:43 +00:00
2022-06-18 18:04:24 +00:00
// 0x20 Intro
public override uint PID { get = > ReadUInt32LittleEndian ( Data . AsSpan ( 0x00 ) ) ; set = > WriteUInt32LittleEndian ( Data . AsSpan ( 0x00 ) , value ) ; }
2023-01-22 04:02:33 +00:00
public override uint ID32 { get = > ReadUInt32LittleEndian ( Data . AsSpan ( 0x04 ) ) ; set = > WriteUInt32LittleEndian ( Data . AsSpan ( 0x04 ) , value ) ; }
public override ushort TID16 { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x04 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x04 ) , value ) ; }
public override ushort SID16 { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x06 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x06 ) , value ) ; }
2022-06-18 18:04:24 +00:00
public override string Nickname
{
get = > StringConverter3 . GetString ( Nickname_Trash , Japanese ) ;
2023-01-22 04:02:33 +00:00
set = > StringConverter3 . SetString ( Nickname_Trash , IsEgg ? EggNameJapanese : value , 10 , Japanese , StringConverterOption . None ) ;
2022-06-18 18:04:24 +00:00
}
public override int Language { get = > Data [ 0x12 ] ; set = > Data [ 0x12 ] = ( byte ) value ; }
public bool FlagIsBadEgg { get = > ( Data [ 0x13 ] & 1 ) ! = 0 ; set = > Data [ 0x13 ] = ( byte ) ( ( Data [ 0x13 ] & ~ 1 ) | ( value ? 1 : 0 ) ) ; }
public bool FlagHasSpecies { get = > ( Data [ 0x13 ] & 2 ) ! = 0 ; set = > Data [ 0x13 ] = ( byte ) ( ( Data [ 0x13 ] & ~ 2 ) | ( value ? 2 : 0 ) ) ; }
public bool FlagIsEgg { get = > ( Data [ 0x13 ] & 4 ) ! = 0 ; set = > Data [ 0x13 ] = ( byte ) ( ( Data [ 0x13 ] & ~ 4 ) | ( value ? 4 : 0 ) ) ; }
public override string OT_Name
{
get = > StringConverter3 . GetString ( OT_Trash , Japanese ) ;
2023-01-22 04:02:33 +00:00
set = > StringConverter3 . SetString ( OT_Trash , value , 7 , Japanese , StringConverterOption . None ) ;
2022-06-18 18:04:24 +00:00
}
public override int MarkValue { get = > SwapBits ( Data [ 0x1B ] , 1 , 2 ) ; set = > Data [ 0x1B ] = ( byte ) SwapBits ( value , 1 , 2 ) ; }
public ushort Checksum { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x1C ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x1C ) , value ) ; }
public ushort Sanity { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x1E ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x1E ) , value ) ; }
2016-06-20 04:22:43 +00:00
2022-06-18 18:04:24 +00:00
#region Block A
2023-01-22 04:02:33 +00:00
public override ushort SpeciesInternal { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x20 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x20 ) , value ) ; } // raw access
2018-12-15 07:26:46 +00:00
2022-08-30 22:00:45 +00:00
public override ushort Species
2022-06-18 18:04:24 +00:00
{
2023-01-22 04:02:33 +00:00
get = > SpeciesConverter . GetNational3 ( SpeciesInternal ) ;
2022-06-18 18:04:24 +00:00
set
2018-12-15 07:26:46 +00:00
{
2023-01-22 04:02:33 +00:00
var s3 = SpeciesConverter . GetInternal3 ( value ) ;
FlagHasSpecies = ( SpeciesInternal = s3 ) ! = 0 ;
2018-12-15 07:26:46 +00:00
}
2022-06-18 18:04:24 +00:00
}
2018-12-15 07:26:46 +00:00
2022-06-18 18:04:24 +00:00
public override int SpriteItem = > ItemConverter . GetItemFuture3 ( ( ushort ) HeldItem ) ;
public override int HeldItem { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x22 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x22 ) , ( ushort ) value ) ; }
public override uint EXP { get = > ReadUInt32LittleEndian ( Data . AsSpan ( 0x24 ) ) ; set = > WriteUInt32LittleEndian ( Data . AsSpan ( 0x24 ) , value ) ; }
private byte PPUps { get = > Data [ 0x28 ] ; set = > Data [ 0x28 ] = value ; }
public override int Move1_PPUps { get = > ( PPUps > > 0 ) & 3 ; set = > PPUps = ( byte ) ( ( PPUps & ~ ( 3 < < 0 ) ) | ( value < < 0 ) ) ; }
public override int Move2_PPUps { get = > ( PPUps > > 2 ) & 3 ; set = > PPUps = ( byte ) ( ( PPUps & ~ ( 3 < < 2 ) ) | ( value < < 2 ) ) ; }
public override int Move3_PPUps { get = > ( PPUps > > 4 ) & 3 ; set = > PPUps = ( byte ) ( ( PPUps & ~ ( 3 < < 4 ) ) | ( value < < 4 ) ) ; }
public override int Move4_PPUps { get = > ( PPUps > > 6 ) & 3 ; set = > PPUps = ( byte ) ( ( PPUps & ~ ( 3 < < 6 ) ) | ( value < < 6 ) ) ; }
public override int OT_Friendship { get = > Data [ 0x29 ] ; set = > Data [ 0x29 ] = ( byte ) value ; }
// Unused 0x2A 0x2B
#endregion
#region Block B
2022-08-27 06:43:36 +00:00
public override ushort Move1 { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x2C ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x2C ) , value ) ; }
public override ushort Move2 { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x2E ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x2E ) , value ) ; }
public override ushort Move3 { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x30 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x30 ) , value ) ; }
public override ushort Move4 { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x32 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x32 ) , value ) ; }
2022-06-18 18:04:24 +00:00
public override int Move1_PP { get = > Data [ 0x34 ] ; set = > Data [ 0x34 ] = ( byte ) value ; }
public override int Move2_PP { get = > Data [ 0x35 ] ; set = > Data [ 0x35 ] = ( byte ) value ; }
public override int Move3_PP { get = > Data [ 0x36 ] ; set = > Data [ 0x36 ] = ( byte ) value ; }
public override int Move4_PP { get = > Data [ 0x37 ] ; set = > Data [ 0x37 ] = ( byte ) value ; }
#endregion
#region Block C
public override int EV_HP { get = > Data [ 0x38 ] ; set = > Data [ 0x38 ] = ( byte ) value ; }
public override int EV_ATK { get = > Data [ 0x39 ] ; set = > Data [ 0x39 ] = ( byte ) value ; }
public override int EV_DEF { get = > Data [ 0x3A ] ; set = > Data [ 0x3A ] = ( byte ) value ; }
public override int EV_SPE { get = > Data [ 0x3B ] ; set = > Data [ 0x3B ] = ( byte ) value ; }
public override int EV_SPA { get = > Data [ 0x3C ] ; set = > Data [ 0x3C ] = ( byte ) value ; }
public override int EV_SPD { get = > Data [ 0x3D ] ; set = > Data [ 0x3D ] = ( byte ) value ; }
public override byte CNT_Cool { get = > Data [ 0x3E ] ; set = > Data [ 0x3E ] = value ; }
public override byte CNT_Beauty { get = > Data [ 0x3F ] ; set = > Data [ 0x3F ] = value ; }
public override byte CNT_Cute { get = > Data [ 0x40 ] ; set = > Data [ 0x40 ] = value ; }
public override byte CNT_Smart { get = > Data [ 0x41 ] ; set = > Data [ 0x41 ] = value ; }
public override byte CNT_Tough { get = > Data [ 0x42 ] ; set = > Data [ 0x42 ] = value ; }
public override byte CNT_Sheen { get = > Data [ 0x43 ] ; set = > Data [ 0x43 ] = value ; }
#endregion
#region Block D
private byte PKRS { get = > Data [ 0x44 ] ; set = > Data [ 0x44 ] = value ; }
public override int PKRS_Days { get = > PKRS & 0xF ; set = > PKRS = ( byte ) ( ( PKRS & ~ 0xF ) | value ) ; }
public override int PKRS_Strain { get = > PKRS > > 4 ; set = > PKRS = ( byte ) ( ( PKRS & 0xF ) | ( value < < 4 ) ) ; }
public override int Met_Location { get = > Data [ 0x45 ] ; set = > Data [ 0x45 ] = ( byte ) value ; }
// Origins
private ushort Origins { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x46 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x46 ) , value ) ; }
public override int Met_Level { get = > Origins & 0x7F ; set = > Origins = ( ushort ) ( ( Origins & ~ 0x7F ) | value ) ; }
public override int Version { get = > ( Origins > > 7 ) & 0xF ; set = > Origins = ( ushort ) ( ( Origins & ~ 0x780 ) | ( ( value & 0xF ) < < 7 ) ) ; }
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 ) ) ; }
2023-06-04 01:52:05 +00:00
private uint IV32 { get = > ReadUInt32LittleEndian ( Data . AsSpan ( 0x48 ) ) ; set = > WriteUInt32LittleEndian ( Data . AsSpan ( 0x48 ) , value ) ; }
2022-06-18 18:04:24 +00:00
public override int IV_HP { get = > ( int ) ( IV32 > > 00 ) & 0x1F ; set = > IV32 = ( IV32 & ~ ( 0x1F u < < 00 ) ) | ( ( value > 31 ? 31 u : ( uint ) value ) < < 00 ) ; }
public override int IV_ATK { get = > ( int ) ( IV32 > > 05 ) & 0x1F ; set = > IV32 = ( IV32 & ~ ( 0x1F u < < 05 ) ) | ( ( value > 31 ? 31 u : ( uint ) value ) < < 05 ) ; }
public override int IV_DEF { get = > ( int ) ( IV32 > > 10 ) & 0x1F ; set = > IV32 = ( IV32 & ~ ( 0x1F u < < 10 ) ) | ( ( value > 31 ? 31 u : ( uint ) value ) < < 10 ) ; }
public override int IV_SPE { get = > ( int ) ( IV32 > > 15 ) & 0x1F ; set = > IV32 = ( IV32 & ~ ( 0x1F u < < 15 ) ) | ( ( value > 31 ? 31 u : ( uint ) value ) < < 15 ) ; }
public override int IV_SPA { get = > ( int ) ( IV32 > > 20 ) & 0x1F ; set = > IV32 = ( IV32 & ~ ( 0x1F u < < 20 ) ) | ( ( value > 31 ? 31 u : ( uint ) value ) < < 20 ) ; }
public override int IV_SPD { get = > ( int ) ( IV32 > > 25 ) & 0x1F ; set = > IV32 = ( IV32 & ~ ( 0x1F u < < 25 ) ) | ( ( value > 31 ? 31 u : ( uint ) value ) < < 25 ) ; }
public override bool IsEgg
{
get = > ( ( IV32 > > 30 ) & 1 ) = = 1 ;
set
2018-12-15 07:26:46 +00:00
{
2022-06-18 18:04:24 +00:00
IV32 = ( IV32 & ~ 0x40000000 u ) | ( value ? 0x40000000 u : 0 ) ;
FlagIsEgg = value ;
if ( value )
2018-12-15 07:26:46 +00:00
{
2022-06-18 18:04:24 +00:00
Nickname = EggNameJapanese ;
Language = ( int ) LanguageID . Japanese ;
2018-12-15 07:26:46 +00:00
}
}
2022-06-18 18:04:24 +00:00
}
2018-12-15 07:26:46 +00:00
2022-06-18 18:04:24 +00:00
public override bool AbilityBit { get = > IV32 > > 31 = = 1 ; set = > IV32 = ( IV32 & 0x7FFFFFFF ) | ( value ? 1 u < < 31 : 0 u ) ; }
private uint RIB0 { get = > ReadUInt32LittleEndian ( Data . AsSpan ( 0x4C ) ) ; set = > WriteUInt32LittleEndian ( Data . AsSpan ( 0x4C ) , value ) ; }
2022-08-24 04:25:22 +00:00
public override byte RibbonCountG3Cool { get = > ( byte ) ( ( RIB0 > > 00 ) & 7 ) ; set = > RIB0 = ( ( RIB0 & ~ ( 7 u < < 00 ) ) | ( ( uint ) ( value & 7 ) < < 00 ) ) ; }
public override byte RibbonCountG3Beauty { get = > ( byte ) ( ( RIB0 > > 03 ) & 7 ) ; set = > RIB0 = ( ( RIB0 & ~ ( 7 u < < 03 ) ) | ( ( uint ) ( value & 7 ) < < 03 ) ) ; }
public override byte RibbonCountG3Cute { get = > ( byte ) ( ( RIB0 > > 06 ) & 7 ) ; set = > RIB0 = ( ( RIB0 & ~ ( 7 u < < 06 ) ) | ( ( uint ) ( value & 7 ) < < 06 ) ) ; }
public override byte RibbonCountG3Smart { get = > ( byte ) ( ( RIB0 > > 09 ) & 7 ) ; set = > RIB0 = ( ( RIB0 & ~ ( 7 u < < 09 ) ) | ( ( uint ) ( value & 7 ) < < 09 ) ) ; }
public override byte RibbonCountG3Tough { get = > ( byte ) ( ( RIB0 > > 12 ) & 7 ) ; set = > RIB0 = ( ( RIB0 & ~ ( 7 u < < 12 ) ) | ( ( uint ) ( value & 7 ) < < 12 ) ) ; }
2022-06-18 18:04:24 +00:00
public override bool RibbonChampionG3 { get = > ( RIB0 & ( 1 < < 15 ) ) = = 1 < < 15 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 15 ) ) | ( value ? 1 u < < 15 : 0 u ) ) ; }
public override bool RibbonWinning { get = > ( RIB0 & ( 1 < < 16 ) ) = = 1 < < 16 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 16 ) ) | ( value ? 1 u < < 16 : 0 u ) ) ; }
public override bool RibbonVictory { get = > ( RIB0 & ( 1 < < 17 ) ) = = 1 < < 17 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 17 ) ) | ( value ? 1 u < < 17 : 0 u ) ) ; }
public override bool RibbonArtist { get = > ( RIB0 & ( 1 < < 18 ) ) = = 1 < < 18 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 18 ) ) | ( value ? 1 u < < 18 : 0 u ) ) ; }
public override bool RibbonEffort { get = > ( RIB0 & ( 1 < < 19 ) ) = = 1 < < 19 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 19 ) ) | ( value ? 1 u < < 19 : 0 u ) ) ; }
public override bool RibbonChampionBattle { get = > ( RIB0 & ( 1 < < 20 ) ) = = 1 < < 20 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 20 ) ) | ( value ? 1 u < < 20 : 0 u ) ) ; }
public override bool RibbonChampionRegional { get = > ( RIB0 & ( 1 < < 21 ) ) = = 1 < < 21 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 21 ) ) | ( value ? 1 u < < 21 : 0 u ) ) ; }
public override bool RibbonChampionNational { get = > ( RIB0 & ( 1 < < 22 ) ) = = 1 < < 22 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 22 ) ) | ( value ? 1 u < < 22 : 0 u ) ) ; }
public override bool RibbonCountry { get = > ( RIB0 & ( 1 < < 23 ) ) = = 1 < < 23 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 23 ) ) | ( value ? 1 u < < 23 : 0 u ) ) ; }
public override bool RibbonNational { get = > ( RIB0 & ( 1 < < 24 ) ) = = 1 < < 24 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 24 ) ) | ( value ? 1 u < < 24 : 0 u ) ) ; }
public override bool RibbonEarth { get = > ( RIB0 & ( 1 < < 25 ) ) = = 1 < < 25 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 25 ) ) | ( value ? 1 u < < 25 : 0 u ) ) ; }
public override bool RibbonWorld { get = > ( RIB0 & ( 1 < < 26 ) ) = = 1 < < 26 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 26 ) ) | ( value ? 1 u < < 26 : 0 u ) ) ; }
public override bool Unused1 { get = > ( RIB0 & ( 1 < < 27 ) ) = = 1 < < 27 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 27 ) ) | ( value ? 1 u < < 27 : 0 u ) ) ; }
public override bool Unused2 { get = > ( RIB0 & ( 1 < < 28 ) ) = = 1 < < 28 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 28 ) ) | ( value ? 1 u < < 28 : 0 u ) ) ; }
public override bool Unused3 { get = > ( RIB0 & ( 1 < < 29 ) ) = = 1 < < 29 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 29 ) ) | ( value ? 1 u < < 29 : 0 u ) ) ; }
public override bool Unused4 { get = > ( RIB0 & ( 1 < < 30 ) ) = = 1 < < 30 ; set = > RIB0 = ( ( RIB0 & ~ ( 1 u < < 30 ) ) | ( value ? 1 u < < 30 : 0 u ) ) ; }
public override bool FatefulEncounter { get = > RIB0 > > 31 = = 1 ; set = > RIB0 = ( RIB0 & ~ ( 1 < < 31 ) ) | ( uint ) ( value ? 1 < < 31 : 0 ) ; }
2023-01-22 04:02:33 +00:00
public override int RibbonCount = > BitOperations . PopCount ( RIB0 & 0 b00000111_11111111_11111111_11111111 ) ;
2022-06-18 18:04:24 +00:00
#endregion
#region Battle Stats
public override int Status_Condition { get = > ReadInt32LittleEndian ( Data . AsSpan ( 0x50 ) ) ; set = > WriteInt32LittleEndian ( Data . AsSpan ( 0x50 ) , value ) ; }
public override int Stat_Level { get = > Data [ 0x54 ] ; set = > Data [ 0x54 ] = ( byte ) value ; }
public sbyte HeldMailID { get = > ( sbyte ) Data [ 0x55 ] ; set = > Data [ 0x55 ] = ( byte ) value ; }
public override int Stat_HPCurrent { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x56 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x56 ) , ( ushort ) value ) ; }
public override int Stat_HPMax { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x58 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x58 ) , ( ushort ) value ) ; }
public override int Stat_ATK { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x5A ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x5A ) , ( ushort ) value ) ; }
public override int Stat_DEF { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x5C ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x5C ) , ( ushort ) value ) ; }
public override int Stat_SPE { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x5E ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x5E ) , ( ushort ) value ) ; }
public override int Stat_SPA { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x60 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x60 ) , ( ushort ) value ) ; }
public override int Stat_SPD { get = > ReadUInt16LittleEndian ( Data . AsSpan ( 0x62 ) ) ; set = > WriteUInt16LittleEndian ( Data . AsSpan ( 0x62 ) , ( ushort ) value ) ; }
#endregion
protected override byte [ ] Encrypt ( )
{
RefreshChecksum ( ) ;
return PokeCrypto . EncryptArray3 ( Data ) ;
}
2018-09-15 05:37:47 +00:00
2023-07-15 18:22:48 +00:00
private ushort CalculateChecksum ( ) = > Checksums . Add16 ( Data . AsSpan ( ) [ 0x20 . . PokeCrypto . SIZE_3STORED ] ) ;
2022-06-18 18:04:24 +00:00
public override void RefreshChecksum ( )
{
FlagIsBadEgg = false ;
2023-07-15 18:22:48 +00:00
Checksum = CalculateChecksum ( ) ;
2022-06-18 18:04:24 +00:00
}
2018-12-15 07:26:46 +00:00
2022-06-18 18:04:24 +00:00
public override bool ChecksumValid = > CalculateChecksum ( ) = = Checksum ;
2020-10-18 16:16:52 +00:00
2022-06-18 18:04:24 +00:00
public PK4 ConvertToPK4 ( )
{
PK4 pk4 = new ( ) // Convert away!
2016-06-20 04:22:43 +00:00
{
2022-06-18 18:04:24 +00:00
PID = PID ,
Species = Species ,
2023-01-22 04:02:33 +00:00
TID16 = TID16 ,
SID16 = SID16 ,
2022-06-18 18:04:24 +00:00
EXP = IsEgg ? Experience . GetEXP ( 5 , PersonalInfo . EXPGrowth ) : EXP ,
Gender = EntityGender . GetFromPID ( Species , PID ) ,
Form = Form ,
// IsEgg = false, -- already false
OT_Friendship = 70 ,
MarkValue = MarkValue & 0 b1111 ,
Language = Language ,
EV_HP = EV_HP ,
EV_ATK = EV_ATK ,
EV_DEF = EV_DEF ,
EV_SPA = EV_SPA ,
EV_SPD = EV_SPD ,
EV_SPE = EV_SPE ,
CNT_Cool = CNT_Cool ,
CNT_Beauty = CNT_Beauty ,
CNT_Cute = CNT_Cute ,
CNT_Smart = CNT_Smart ,
CNT_Tough = CNT_Tough ,
CNT_Sheen = CNT_Sheen ,
Move1 = Move1 ,
Move2 = Move2 ,
Move3 = Move3 ,
Move4 = Move4 ,
Move1_PPUps = Move1_PPUps ,
Move2_PPUps = Move2_PPUps ,
Move3_PPUps = Move3_PPUps ,
Move4_PPUps = Move4_PPUps ,
IV_HP = IV_HP ,
IV_ATK = IV_ATK ,
IV_DEF = IV_DEF ,
IV_SPA = IV_SPA ,
IV_SPD = IV_SPD ,
IV_SPE = IV_SPE ,
Ability = Ability ,
Version = Version ,
Ball = Ball ,
PKRS_Strain = PKRS_Strain ,
PKRS_Days = PKRS_Days ,
OT_Gender = OT_Gender ,
2023-08-12 23:01:16 +00:00
MetDate = EncounterDate . GetDateNDS ( ) ,
2022-06-18 18:04:24 +00:00
Met_Level = CurrentLevel ,
Met_Location = Locations . Transfer3 , // Pal Park
RibbonChampionG3 = RibbonChampionG3 ,
RibbonWinning = RibbonWinning ,
RibbonVictory = RibbonVictory ,
RibbonArtist = RibbonArtist ,
RibbonEffort = RibbonEffort ,
RibbonChampionBattle = RibbonChampionBattle ,
RibbonChampionRegional = RibbonChampionRegional ,
RibbonChampionNational = RibbonChampionNational ,
RibbonCountry = RibbonCountry ,
RibbonNational = RibbonNational ,
RibbonEarth = RibbonEarth ,
RibbonWorld = RibbonWorld ,
// byte -> bool contest ribbons
RibbonG3Cool = RibbonCountG3Cool > 0 ,
RibbonG3CoolSuper = RibbonCountG3Cool > 1 ,
RibbonG3CoolHyper = RibbonCountG3Cool > 2 ,
RibbonG3CoolMaster = RibbonCountG3Cool > 3 ,
RibbonG3Beauty = RibbonCountG3Beauty > 0 ,
RibbonG3BeautySuper = RibbonCountG3Beauty > 1 ,
RibbonG3BeautyHyper = RibbonCountG3Beauty > 2 ,
RibbonG3BeautyMaster = RibbonCountG3Beauty > 3 ,
RibbonG3Cute = RibbonCountG3Cute > 0 ,
RibbonG3CuteSuper = RibbonCountG3Cute > 1 ,
RibbonG3CuteHyper = RibbonCountG3Cute > 2 ,
RibbonG3CuteMaster = RibbonCountG3Cute > 3 ,
RibbonG3Smart = RibbonCountG3Smart > 0 ,
RibbonG3SmartSuper = RibbonCountG3Smart > 1 ,
RibbonG3SmartHyper = RibbonCountG3Smart > 2 ,
RibbonG3SmartMaster = RibbonCountG3Smart > 3 ,
RibbonG3Tough = RibbonCountG3Tough > 0 ,
RibbonG3ToughSuper = RibbonCountG3Tough > 1 ,
RibbonG3ToughHyper = RibbonCountG3Tough > 2 ,
RibbonG3ToughMaster = RibbonCountG3Tough > 3 ,
FatefulEncounter = FatefulEncounter ,
} ;
2018-09-15 05:37:47 +00:00
2022-06-18 18:04:24 +00:00
// Yay for reusing string buffers! The game allocates a buffer and reuses it when creating strings.
// Trash from the {unknown source} is currently in buffer. Set it to the Nickname region.
2023-01-22 04:02:33 +00:00
var trash = StringConverter345 . GetTrashBytes ( pk4 . Language ) ;
var nickTrash = pk4 . Nickname_Trash [ 4. . ] ; // min of 1 char and terminator, ignore first 2.
trash . CopyTo ( nickTrash ) ;
2022-06-18 18:04:24 +00:00
pk4 . Nickname = IsEgg ? SpeciesName . GetSpeciesNameGeneration ( pk4 . Species , pk4 . Language , 4 ) : Nickname ;
pk4 . IsNicknamed = ! IsEgg & & IsNicknamed ;
2016-06-20 04:22:43 +00:00
2022-06-18 18:04:24 +00:00
// Trash from the current string (Nickname) is in our string buffer. Slap the OT name over-top.
2023-01-22 19:43:13 +00:00
var destOT = pk4 . OT_Trash ;
nickTrash [ . . destOT . Length ] . CopyTo ( destOT ) ;
2022-06-18 18:04:24 +00:00
pk4 . OT_Name = OT_Name ;
2018-02-03 20:42:06 +00:00
2022-06-18 18:04:24 +00:00
if ( HeldItem > 0 )
2018-02-03 20:42:06 +00:00
{
2022-06-18 18:04:24 +00:00
ushort item = ItemConverter . GetItemFuture3 ( ( ushort ) HeldItem ) ;
if ( ItemConverter . IsItemTransferable34 ( item ) )
pk4 . HeldItem = item ;
2018-02-03 20:42:06 +00:00
}
2018-09-15 05:37:47 +00:00
2022-06-18 18:04:24 +00:00
// Remove HM moves
2022-08-27 06:43:36 +00:00
ReadOnlySpan < ushort > banned = LearnSource3 . HM_3 ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
if ( banned . Contains ( Move1 ) ) pk4 . Move1 = 0 ;
if ( banned . Contains ( Move2 ) ) pk4 . Move2 = 0 ;
if ( banned . Contains ( Move3 ) ) pk4 . Move3 = 0 ;
if ( banned . Contains ( Move4 ) ) pk4 . Move4 = 0 ;
2022-06-18 18:04:24 +00:00
pk4 . FixMoves ( ) ;
pk4 . HealPP ( ) ;
pk4 . RefreshChecksum ( ) ;
return pk4 ;
}
public XK3 ConvertToXK3 ( )
{
var pk = ConvertTo < XK3 > ( ) ;
2022-06-19 16:26:28 +00:00
// Set these even if the settings don't SetPKM
pk . CurrentRegion = 2 ; // NTSC-U
pk . OriginalRegion = 2 ; // NTSC-U
2022-06-18 18:04:24 +00:00
pk . ResetPartyStats ( ) ;
return pk ;
}
public CK3 ConvertToCK3 ( )
{
var pk = ConvertTo < CK3 > ( ) ;
2022-06-19 16:26:28 +00:00
// Set these even if the settings don't SetPKM
pk . CurrentRegion = 2 ; // NTSC-U
pk . OriginalRegion = 2 ; // NTSC-U
2022-06-18 18:04:24 +00:00
pk . ResetPartyStats ( ) ;
return pk ;
2016-06-20 04:22:43 +00:00
}
}