2019-01-07 00:22:45 +00:00
using static PKHeX . Core . EvolutionType ;
2018-05-19 19:07:50 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
/// <summary>
/// Criteria for evolving to this branch in the <see cref="EvolutionTree"/>
/// </summary>
public sealed class EvolutionMethod
2018-05-19 19:07:50 +00:00
{
/// <summary>
2022-06-18 18:04:24 +00:00
/// Evolution Method
2018-05-19 19:07:50 +00:00
/// </summary>
2022-06-18 18:04:24 +00:00
public readonly int Method ;
2020-01-25 23:42:17 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Evolve to Species
/// </summary>
public readonly int Species ;
2021-06-06 18:49:41 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Conditional Argument (different from <see cref="Level"/>)
/// </summary>
public readonly int Argument ;
2019-12-07 01:36:36 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Conditional Argument (different from <see cref="Argument"/>)
/// </summary>
public readonly byte Level ;
2019-11-16 19:01:00 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Destination Form
/// </summary>
/// <remarks>Is <see cref="AnyForm"/> if the evolved form isn't modified. Special consideration for <see cref="LevelUpFormFemale1"/>, which forces 1.</remarks>
public readonly int Form ;
2018-05-19 19:07:50 +00:00
2022-06-18 18:04:24 +00:00
private const int AnyForm = - 1 ;
2018-05-19 19:07:50 +00:00
2022-06-18 18:04:24 +00:00
// Not stored in binary data
public bool RequiresLevelUp ; // tracks if this method requires a Level Up, lazily set
2022-02-05 01:35:15 +00:00
2022-06-18 18:04:24 +00:00
public EvolutionMethod ( int method , int species , int argument = 0 , byte level = 0 , int form = AnyForm )
{
Method = method ;
Species = species ;
Argument = argument ;
Form = form ;
Level = level ;
}
2018-05-19 19:07:50 +00:00
2022-06-18 18:04:24 +00:00
public override string ToString ( ) = > $"{(Species) Species}-{Form} [{Argument}] @ {Level}{(RequiresLevelUp ? " X " : " ")}" ;
2018-05-19 19:07:50 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Returns the form that the Pok<6F> mon will have after evolution.
/// </summary>
/// <param name="form">Un-evolved Form ID</param>
public int GetDestinationForm ( int form )
{
if ( Method = = ( int ) LevelUpFormFemale1 )
return 1 ;
if ( Form = = AnyForm )
return form ;
return Form ;
}
2022-02-05 01:35:15 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Checks the <see cref="EvolutionMethod"/> for validity by comparing against the <see cref="PKM"/> data.
/// </summary>
/// <param name="pk">Entity to check</param>
/// <param name="lvl">Current level</param>
/// <param name="skipChecks">Option to skip some comparisons to return a 'possible' evolution.</param>
/// <returns>True if a evolution criteria is valid.</returns>
public bool Valid ( PKM pk , int lvl , bool skipChecks )
{
RequiresLevelUp = false ;
switch ( ( EvolutionType ) Method )
2022-02-05 01:35:15 +00:00
{
2022-06-18 18:04:24 +00:00
case UseItem or UseItemWormhole or UseItemFullMoon :
case CriticalHitsInBattle or HitPointsLostInBattle or Spin :
case UseAgileStyleMoves or UseStrongStyleMoves :
case TowerOfDarkness or TowerOfWaters :
return true ;
case UseItemMale or RecoilDamageMale :
return pk . Gender = = 0 ;
case UseItemFemale or RecoilDamageFemale :
return pk . Gender = = 1 ;
case Trade or TradeHeldItem or TradeShelmetKarrablast :
return ! pk . IsUntraded | | skipChecks ;
// Special Level Up Cases -- return false if invalid
case LevelUpNatureAmped or LevelUpNatureLowKey when GetAmpLowKeyResult ( pk . Nature ) ! = pk . Form & & ! skipChecks :
return false ;
case LevelUpBeauty when pk is not IContestStats s | | s . CNT_Beauty < Argument :
return skipChecks ;
case LevelUpMale when pk . Gender ! = 0 :
return false ;
case LevelUpFemale when pk . Gender ! = 1 :
return false ;
case LevelUpFormFemale1 when pk . Gender ! = 1 | | pk . Form ! = 1 :
return false ;
case LevelUpVersion or LevelUpVersionDay or LevelUpVersionNight when ( ( pk . Version & 1 ) ! = ( Argument & 1 ) & & pk . IsUntraded ) | | skipChecks :
return skipChecks ; // Version checks come in pairs, check for any pair match
// Level Up (any); the above Level Up (with condition) cases will reach here if they were valid
default :
if ( IsThresholdCheckMode ( pk ) )
return lvl > = Level ;
if ( Level = = 0 & & lvl < 2 )
return false ;
if ( lvl < Level )
return false ;
RequiresLevelUp = true ;
if ( skipChecks )
return lvl > = Level ;
// Check Met Level for extra validity
return HasMetLevelIncreased ( pk , lvl ) ;
2022-02-05 01:35:15 +00:00
}
2022-06-18 18:04:24 +00:00
}
2019-01-07 00:22:45 +00:00
2022-06-18 18:04:24 +00:00
private static bool IsThresholdCheckMode ( PKM pk )
{
// Starting in Legends: Arceus, level-up evolutions can be triggered if the current level is >= criteria.
// This allows for evolving over-leveled captures immediately without leveling up from capture level.
return pk is PA8 ;
}
2020-12-25 18:58:33 +00:00
2022-06-18 18:04:24 +00:00
private bool HasMetLevelIncreased ( PKM pk , int lvl )
{
int origin = pk . Generation ;
return origin switch
{
// No met data in RBY; No met data in GS, Crystal met data can be reset
1 or 2 = > true ,
2020-12-25 18:58:33 +00:00
2022-06-18 18:04:24 +00:00
// Pal Park / PokeTransfer updates Met Level
3 or 4 = > pk . Format > origin | | pk . Met_Level < lvl ,
2020-12-25 18:58:33 +00:00
2022-06-18 18:04:24 +00:00
// 5=>6 and later transfers keep current level
> = 5 = > lvl > = Level & & ( ! pk . IsNative | | pk . Met_Level < lvl ) ,
2018-05-19 19:07:50 +00:00
2022-06-18 18:04:24 +00:00
_ = > false ,
2021-12-05 01:56:56 +00:00
} ;
2022-06-18 18:04:24 +00:00
}
2019-11-16 19:01:00 +00:00
2022-06-18 18:04:24 +00:00
public EvoCriteria GetEvoCriteria ( ushort species , byte form , byte lvl ) = > new ( )
{
Species = species ,
Form = form ,
LevelMax = lvl ,
LevelMin = 0 ,
Method = ( EvolutionType ) Method ,
} ;
public static int GetAmpLowKeyResult ( int n )
{
var index = n - 1 ;
if ( ( uint ) index > 22 )
return 0 ;
return ( 0 b_0101_1011_1100_1010_0101_0001 > > index ) & 1 ;
2018-05-19 19:07:50 +00:00
}
2021-01-31 03:58:05 +00:00
}