2022-06-18 18:04:24 +00:00
using System ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
/// <summary>
/// Contains extension logic for modifying <see cref="PKM"/> data.
/// </summary>
public static class CommonEdits
2018-03-11 02:03:09 +00:00
{
/// <summary>
2022-06-18 18:04:24 +00:00
/// Setting which enables/disables automatic manipulation of <see cref="PKM.MarkValue"/> when importing from a <see cref="IBattleTemplate"/>.
/// </summary>
public static bool ShowdownSetIVMarkings { get ; set ; } = true ;
/// <summary>
/// Setting which causes the <see cref="PKM.StatNature"/> to the <see cref="PKM.Nature"/> in Gen8+ formats.
2018-03-11 02:03:09 +00:00
/// </summary>
2022-06-18 18:04:24 +00:00
public static bool ShowdownSetBehaviorNature { get ; set ; }
/// <summary>
/// Sets the <see cref="PKM.Nickname"/> to the provided value.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="nick"><see cref="PKM.Nickname"/> to set. If no nickname is provided, the <see cref="PKM.Nickname"/> is set to the default value for its current language and format.</param>
public static void SetNickname ( this PKM pk , string nick )
2018-03-11 02:03:09 +00:00
{
2022-06-26 06:08:28 +00:00
if ( nick . Length = = 0 )
2018-03-11 02:03:09 +00:00
{
2022-06-18 18:04:24 +00:00
pk . ClearNickname ( ) ;
return ;
2019-02-12 05:49:05 +00:00
}
2022-06-18 18:04:24 +00:00
pk . IsNicknamed = true ;
pk . Nickname = nick ;
}
2019-02-12 05:49:05 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Clears the <see cref="PKM.Nickname"/> to the default value.
/// </summary>
/// <param name="pk"></param>
public static string ClearNickname ( this PKM pk )
{
pk . IsNicknamed = false ;
string nick = SpeciesName . GetSpeciesNameGeneration ( pk . Species , pk . Language , pk . Format ) ;
pk . Nickname = nick ;
if ( pk is GBPKM pk12 )
pk12 . SetNotNicknamed ( ) ;
return nick ;
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets the <see cref="PKM.Ability"/> value by sanity checking the provided <see cref="PKM.Ability"/> against the possible pool of abilities.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="abil">Desired <see cref="PKM.Ability"/> to set.</param>
public static void SetAbility ( this PKM pk , int abil )
{
if ( abil < 0 )
return ;
2022-09-02 17:20:19 +00:00
var index = pk . PersonalInfo . GetIndexOfAbility ( abil ) ;
2022-06-18 18:04:24 +00:00
index = Math . Max ( 0 , index ) ;
pk . SetAbilityIndex ( index ) ;
}
/// <summary>
/// Sets the <see cref="PKM.Ability"/> value based on the provided ability index (0-2)
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="index">Desired <see cref="PKM.AbilityNumber"/> (shifted by 1) to set.</param>
public static void SetAbilityIndex ( this PKM pk , int index )
{
if ( pk is PK5 pk5 & & index = = 2 )
pk5 . HiddenAbility = true ;
else if ( pk . Format < = 5 )
pk . PID = EntityPID . GetRandomPID ( Util . Rand , pk . Species , pk . Gender , pk . Version , pk . Nature , pk . Form , ( uint ) ( index * 0x10001 ) ) ;
pk . RefreshAbility ( index ) ;
}
/// <summary>
/// Sets a Random <see cref="PKM.EncryptionConstant"/> value. The <see cref="PKM.EncryptionConstant"/> is not updated if the value should match the <see cref="PKM.PID"/> instead.
/// </summary>
/// <remarks>Accounts for Wurmple evolutions.</remarks>
/// <param name="pk">Pokémon to modify.</param>
public static void SetRandomEC ( this PKM pk )
{
int gen = pk . Generation ;
if ( gen is 3 or 4 or 5 )
2018-03-11 02:03:09 +00:00
{
2022-06-18 18:04:24 +00:00
pk . EncryptionConstant = pk . PID ;
return ;
2018-09-03 17:30:35 +00:00
}
2022-12-17 21:17:24 +00:00
pk . EncryptionConstant = GetComplicatedEC ( pk ) ;
2022-06-18 18:04:24 +00:00
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets the <see cref="PKM.IsShiny"/> derived value.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="shiny">Desired <see cref="PKM.IsShiny"/> state to set.</param>
public static bool SetIsShiny ( this PKM pk , bool shiny ) = > shiny ? SetShiny ( pk ) : pk . SetUnshiny ( ) ;
2019-05-11 21:25:58 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Makes a <see cref="PKM"/> shiny.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="type">Shiny type to force. Only use Always* or Random</param>
/// <returns>Returns true if the <see cref="PKM"/> data was modified.</returns>
public static bool SetShiny ( PKM pk , Shiny type = Shiny . Random )
{
if ( pk . IsShiny & & type . IsValid ( pk ) )
return false ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
if ( type = = Shiny . Random | | pk . FatefulEncounter | | pk . Version = = ( int ) GameVersion . GO | | pk . Format < = 2 )
2018-03-11 02:03:09 +00:00
{
2022-06-18 18:04:24 +00:00
pk . SetShiny ( ) ;
return true ;
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
do { pk . SetShiny ( ) ; }
while ( ! type . IsValid ( pk ) ) ;
2019-11-21 04:38:05 +00:00
2022-06-18 18:04:24 +00:00
return true ;
}
2020-02-21 23:02:16 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Makes a <see cref="PKM"/> not-shiny.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <returns>Returns true if the <see cref="PKM"/> data was modified.</returns>
public static bool SetUnshiny ( this PKM pk )
{
if ( ! pk . IsShiny )
return false ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
pk . SetPIDGender ( pk . Gender ) ;
return true ;
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets the <see cref="PKM.Nature"/> value, with special consideration for the <see cref="PKM.Format"/> values which derive the <see cref="PKM.Nature"/> value.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="nature">Desired <see cref="PKM.Nature"/> value to set.</param>
public static void SetNature ( this PKM pk , int nature )
{
2023-01-22 04:02:33 +00:00
var value = Math . Clamp ( nature , ( int ) Nature . Hardy , ( int ) Nature . Quirky ) ;
2022-06-18 18:04:24 +00:00
var format = pk . Format ;
if ( format > = 8 )
pk . StatNature = value ;
else if ( format is 3 or 4 )
pk . SetPIDNature ( value ) ;
else
pk . Nature = value ;
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Copies <see cref="IBattleTemplate"/> details to the <see cref="PKM"/>.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="Set"><see cref="IBattleTemplate"/> details to copy from.</param>
public static void ApplySetDetails ( this PKM pk , IBattleTemplate Set )
{
pk . Species = Math . Min ( pk . MaxSpeciesID , Set . Species ) ;
pk . Form = Set . Form ;
2022-07-01 00:24:01 +00:00
if ( Set . Moves [ 0 ] ! = 0 )
pk . SetMoves ( Set . Moves , true ) ;
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
pk . ApplyHeldItem ( Set . HeldItem , Set . Context ) ;
2022-06-18 18:04:24 +00:00
pk . CurrentLevel = Set . Level ;
pk . CurrentFriendship = Set . Friendship ;
pk . SetIVs ( Set . IVs ) ;
if ( pk is GBPKM gb )
2018-03-11 02:03:09 +00:00
{
2022-06-18 18:04:24 +00:00
// In Generation 1/2 Format sets, when IVs are not specified with a Hidden Power set, we might not have the hidden power type.
// Under this scenario, just force the Hidden Power type.
2022-08-27 06:43:36 +00:00
if ( Array . IndexOf ( Set . Moves , ( ushort ) Move . HiddenPower ) ! = - 1 & & pk . HPType ! = Set . HiddenPowerType )
2022-06-26 06:08:28 +00:00
{
2023-04-15 08:58:37 +00:00
if ( Set . IVs . AsSpan ( ) . IndexOfAny ( 30 , 31 ) > = 0 )
2022-06-26 06:08:28 +00:00
pk . SetHiddenPower ( Set . HiddenPowerType ) ;
}
2022-06-18 18:04:24 +00:00
// In Generation 1/2 Format sets, when EVs are not specified at all, it implies maximum EVs instead!
// Under this scenario, just apply maximum EVs (65535).
2023-04-15 08:58:37 +00:00
if ( Set . EVs . AsSpan ( ) . IndexOfAnyExcept ( 0 ) = = - 1 )
2022-06-18 18:04:24 +00:00
gb . MaxEVs ( ) ;
2018-03-11 02:03:09 +00:00
else
2022-06-26 06:08:28 +00:00
pk . SetEVs ( Set . EVs ) ;
2018-03-11 02:03:09 +00:00
}
2022-06-18 18:04:24 +00:00
else
2018-03-11 02:03:09 +00:00
{
2022-06-26 06:08:28 +00:00
pk . SetEVs ( Set . EVs ) ;
2022-06-18 18:04:24 +00:00
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
// IVs have no side effects such as hidden power type in gen 8
// therefore all specified IVs are deliberate and should not be Hyper Trained for pokemon met in gen 8
2023-01-22 04:02:33 +00:00
if ( pk . Generation < 8 )
2022-06-18 18:04:24 +00:00
pk . SetSuggestedHyperTrainingData ( Set . IVs ) ;
2020-08-15 04:49:01 +00:00
2022-06-18 18:04:24 +00:00
if ( ShowdownSetIVMarkings )
pk . SetMarkings ( ) ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
pk . SetNickname ( Set . Nickname ) ;
pk . SetSaneGender ( Set . Gender ) ;
2022-02-07 23:40:02 +00:00
2022-06-18 18:04:24 +00:00
if ( Legal . IsPPUpAvailable ( pk ) )
pk . SetMaximumPPUps ( Set . Moves ) ;
2021-01-03 03:58:25 +00:00
2022-06-18 18:04:24 +00:00
if ( pk . Format > = 3 )
{
pk . SetAbility ( Set . Ability ) ;
pk . SetNature ( Set . Nature ) ;
}
2021-01-03 03:58:25 +00:00
2022-06-18 18:04:24 +00:00
pk . SetIsShiny ( Set . Shiny ) ;
pk . SetRandomEC ( ) ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
if ( pk is IAwakened a )
{
a . SetSuggestedAwakenedValues ( pk ) ;
if ( pk is PB7 b )
2018-11-20 02:26:46 +00:00
{
2022-06-18 18:04:24 +00:00
for ( int i = 0 ; i < 6 ; i + + )
b . SetEV ( i , 0 ) ;
b . ResetCalculatedValues ( ) ;
2018-11-20 02:26:46 +00:00
}
2022-06-18 18:04:24 +00:00
}
if ( pk is IGanbaru g )
g . SetSuggestedGanbaruValues ( pk ) ;
2019-11-26 01:32:10 +00:00
2022-06-18 18:04:24 +00:00
if ( pk is IGigantamax c )
c . CanGigantamax = Set . CanGigantamax ;
if ( pk is IDynamaxLevel d )
2022-08-04 00:10:00 +00:00
d . DynamaxLevel = d . GetSuggestedDynamaxLevel ( pk , requested : Set . DynamaxLevel ) ;
2022-11-25 01:42:17 +00:00
if ( pk is ITeraType tera )
2022-11-30 04:06:35 +00:00
{
var type = Set . TeraType = = MoveType . Any ? ( MoveType ) pk . PersonalInfo . Type1 : Set . TeraType ;
tera . SetTeraType ( type ) ;
}
2018-11-11 04:21:36 +00:00
2022-11-25 01:42:17 +00:00
if ( pk is ITechRecord t )
2022-06-18 18:04:24 +00:00
{
t . ClearRecordFlags ( ) ;
t . SetRecordFlags ( Set . Moves ) ;
}
if ( pk is IMoveShop8Mastery s )
s . SetMoveShopFlags ( Set . Moves , pk ) ;
2019-11-24 14:06:08 +00:00
2022-06-18 18:04:24 +00:00
if ( ShowdownSetBehaviorNature & & pk . Format > = 8 )
pk . Nature = pk . StatNature ;
2020-03-19 20:47:25 +00:00
2022-06-18 18:04:24 +00:00
var legal = new LegalityAnalysis ( pk ) ;
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 ( legal . Parsed & & ! MoveResult . AllValid ( legal . Info . Relearn ) )
2023-03-22 01:19:55 +00:00
pk . SetRelearnMoves ( legal ) ;
2022-06-18 18:04:24 +00:00
pk . ResetPartyStats ( ) ;
pk . RefreshChecksum ( ) ;
}
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets the <see cref="PKM.HeldItem"/> value depending on the current format and the provided item index & format.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="item">Held Item to apply</param>
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
/// <param name="context">Format required for importing</param>
public static void ApplyHeldItem ( this PKM pk , int item , EntityContext context )
2022-06-18 18:04:24 +00:00
{
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
item = ItemConverter . GetItemForFormat ( item , context , pk . Context ) ;
2022-06-18 18:04:24 +00:00
pk . HeldItem = ( ( uint ) item > pk . MaxItemID ) ? 0 : item ;
}
2018-04-26 01:45:31 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
2022-06-26 06:08:28 +00:00
/// Sets one of the <see cref="EffortValues"/> based on its index within the array.
2022-06-18 18:04:24 +00:00
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="index">Index to set to</param>
/// <param name="value">Value to set</param>
public static int SetEV ( this PKM pk , int index , int value ) = > index switch
{
0 = > pk . EV_HP = value ,
1 = > pk . EV_ATK = value ,
2 = > pk . EV_DEF = value ,
3 = > pk . EV_SPE = value ,
4 = > pk . EV_SPA = value ,
5 = > pk . EV_SPD = value ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( index ) ) ,
} ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets one of the <see cref="PKM.IVs"/> based on its index within the array.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="index">Index to set to</param>
/// <param name="value">Value to set</param>
public static int SetIV ( this PKM pk , int index , int value ) = > index switch
{
0 = > pk . IV_HP = value ,
1 = > pk . IV_ATK = value ,
2 = > pk . IV_DEF = value ,
3 = > pk . IV_SPE = value ,
4 = > pk . IV_SPA = value ,
5 = > pk . IV_SPD = value ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( index ) ) ,
} ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
2022-06-26 06:08:28 +00:00
/// Fetches the highest value the provided <see cref="EffortValues"/> index can be while considering others.
2022-06-18 18:04:24 +00:00
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="index">Index to fetch for</param>
/// <returns>Highest value the value can be.</returns>
public static int GetMaximumEV ( this PKM pk , int index )
{
if ( pk . Format < 3 )
return ushort . MaxValue ;
2018-03-11 02:03:09 +00:00
2022-06-18 18:04:24 +00:00
var sum = pk . EVTotal - pk . GetEV ( index ) ;
int remaining = 510 - sum ;
2023-01-22 04:02:33 +00:00
return Math . Clamp ( remaining , 0 , 252 ) ;
2022-06-18 18:04:24 +00:00
}
2018-04-22 19:43:18 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Fetches the highest value the provided <see cref="PKM.IVs"/>.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="index">Index to fetch for</param>
/// <param name="allow30">Causes the returned value to be dropped down -1 if the value is already at a maximum.</param>
/// <returns>Highest value the value can be.</returns>
public static int GetMaximumIV ( this PKM pk , int index , bool allow30 = false )
{
if ( pk . GetIV ( index ) = = pk . MaxIV & & allow30 )
return pk . MaxIV - 1 ;
return pk . MaxIV ;
}
2018-12-30 06:19:44 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Force hatches a PKM by applying the current species name and a valid Met Location from the origin game.
/// </summary>
/// <param name="pk">PKM to apply hatch details to</param>
2022-12-04 08:43:44 +00:00
/// <param name="tr">Trainer to force hatch with if Version is not currently set.</param>
2022-06-18 18:04:24 +00:00
/// <param name="reHatch">Re-hatch already hatched <see cref="PKM"/> inputs</param>
2022-12-04 08:43:44 +00:00
public static void ForceHatchPKM ( this PKM pk , ITrainerInfo ? tr = null , bool reHatch = false )
2022-06-18 18:04:24 +00:00
{
if ( ! pk . IsEgg & & ! reHatch )
return ;
pk . IsEgg = false ;
pk . ClearNickname ( ) ;
pk . CurrentFriendship = pk . PersonalInfo . BaseFriendship ;
if ( pk . IsTradedEgg )
pk . Egg_Location = pk . Met_Location ;
2022-12-04 08:43:44 +00:00
if ( pk . Version = = 0 )
2022-12-04 15:52:31 +00:00
pk . Version = ( int ) EggStateLegality . GetEggHatchVersion ( pk , ( GameVersion ) ( tr ? . Game ? ? RecentTrainerCache . Game ) ) ;
2022-06-18 18:04:24 +00:00
var loc = EncounterSuggestion . GetSuggestedEggMetLocation ( pk ) ;
if ( loc > = 0 )
pk . Met_Location = loc ;
2023-01-22 04:02:33 +00:00
pk . MetDate = DateOnly . FromDateTime ( DateTime . Today ) ;
2022-06-18 18:04:24 +00:00
if ( pk . Gen6 )
pk . SetHatchMemory6 ( ) ;
}
2018-05-02 02:24:47 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Force hatches a PKM by applying the current species name and a valid Met Location from the origin game.
/// </summary>
/// <param name="pk">PKM to apply hatch details to</param>
/// <param name="origin">Game the egg originated from</param>
/// <param name="dest">Game the egg is currently present on</param>
public static void SetEggMetData ( this PKM pk , GameVersion origin , GameVersion dest )
{
bool traded = origin ! = dest ;
2023-01-22 04:02:33 +00:00
var today = pk . MetDate = DateOnly . FromDateTime ( DateTime . Today ) ;
2022-06-18 18:04:24 +00:00
pk . Egg_Location = EncounterSuggestion . GetSuggestedEncounterEggLocationEgg ( pk . Generation , origin , traded ) ;
pk . EggMetDate = today ;
}
2018-05-02 02:24:47 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Maximizes the <see cref="PKM.CurrentFriendship"/>. If the <see cref="PKM.IsEgg"/>, the hatch counter is set to 1.
/// </summary>
/// <param name="pk">PKM to apply hatch details to</param>
public static void MaximizeFriendship ( this PKM pk )
{
if ( pk . IsEgg )
pk . OT_Friendship = 1 ;
else
pk . CurrentFriendship = byte . MaxValue ;
if ( pk is ICombatPower pb )
pb . ResetCP ( ) ;
}
2018-07-14 22:08:14 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Maximizes the <see cref="PKM.CurrentLevel"/>. If the <see cref="PKM.IsEgg"/>, the <see cref="PKM"/> is ignored.
/// </summary>
/// <param name="pk">PKM to apply hatch details to</param>
public static void MaximizeLevel ( this PKM pk )
{
if ( pk . IsEgg )
return ;
pk . CurrentLevel = 100 ;
if ( pk is ICombatPower pb )
pb . ResetCP ( ) ;
}
2019-04-30 00:36:29 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets the <see cref="PKM.Nickname"/> to its default value.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="la">Precomputed optional</param>
public static void SetDefaultNickname ( this PKM pk , LegalityAnalysis la )
{
2023-01-22 04:02:33 +00:00
if ( la is { Parsed : true , EncounterOriginal : EncounterTrade { HasNickname : true } t } )
2022-06-18 18:04:24 +00:00
pk . SetNickname ( t . GetNickname ( pk . Language ) ) ;
else
pk . ClearNickname ( ) ;
}
2019-04-30 00:36:29 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Sets the <see cref="PKM.Nickname"/> to its default value.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
public static void SetDefaultNickname ( this PKM pk ) = > pk . SetDefaultNickname ( new LegalityAnalysis ( pk ) ) ;
private static readonly string [ ] PotentialUnicode = { "★☆☆☆" , "★★☆☆" , "★★★☆" , "★★★★" } ;
private static readonly string [ ] PotentialNoUnicode = { "+" , "++" , "+++" , "++++" } ;
/// <summary>
/// Gets the Potential evaluation of the input <see cref="pk"/>.
/// </summary>
/// <param name="pk">Pokémon to analyze.</param>
/// <param name="unicode">Returned value is unicode or not</param>
/// <returns>Potential string</returns>
public static string GetPotentialString ( this PKM pk , bool unicode = true )
{
var arr = unicode ? PotentialUnicode : PotentialNoUnicode ;
return arr [ pk . PotentialRating ] ;
}
// Extensions
/// <summary>
/// Gets the Location Name for the <see cref="PKM"/>
/// </summary>
/// <param name="pk">PKM to fetch data for</param>
/// <param name="eggmet">Location requested is the egg obtained location, not met location.</param>
/// <returns>Location string</returns>
public static string GetLocationString ( this PKM pk , bool eggmet )
{
if ( pk . Format < 2 )
return string . Empty ;
int location = eggmet ? pk . Egg_Location : pk . Met_Location ;
return GameInfo . GetLocationName ( eggmet , location , pk . Format , pk . Generation , ( GameVersion ) pk . Version ) ;
2018-03-11 02:03:09 +00:00
}
2022-12-17 21:17:24 +00:00
/// <summary>
/// Gets a <see cref="PKM.EncryptionConstant"/> to match the requested option.
/// </summary>
public static uint GetComplicatedEC ( ISpeciesForm pk , char option = ' ' )
{
var rng = Util . Rand ;
uint rand = rng . Rand32 ( ) ;
uint mod = 1 , noise = 0 ;
if ( pk . Species is > = ( int ) Species . Wurmple and < = ( int ) Species . Dustox )
{
mod = 10 ;
bool lower = option is '0' or 'B' or 'S' | | WurmpleUtil . GetWurmpleEvoGroup ( pk . Species ) = = 0 ;
noise = ( lower ? 0 u : 5 u ) + ( uint ) rng . Next ( 0 , 5 ) ;
}
else if ( pk . Species is ( int ) Species . Dunsparce or ( int ) Species . Dudunsparce or ( int ) Species . Tandemaus or ( int ) Species . Maushold )
{
mod = 100 ;
noise = option switch
{
'0' or '3' = > 0 u ,
_ when pk . Species is ( int ) Species . Dudunsparce & & pk . Form = = 1 = > 0 , // 3 Segment
_ when pk . Species is ( int ) Species . Maushold & & pk . Form = = 0 = > 0 , // Family of 3
2023-01-22 04:02:33 +00:00
_ = > ( uint ) rng . Next ( 1 , 100 ) ,
2022-12-17 21:17:24 +00:00
} ;
}
else if ( option is > = '0' and < = '5' )
{
mod = 6 ;
noise = ( uint ) ( option - '0' ) ;
}
return unchecked ( rand - ( rand % mod ) + noise ) ;
}
2018-03-11 02:03:09 +00:00
}