2021-05-16 04:41:04 +00:00
|
|
|
using static PKHeX.Core.EvolutionRestrictions;
|
2017-06-07 03:52:21 +00:00
|
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
namespace PKHeX.Core;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Verify Evolution Information for a matched <see cref="IEncounterable"/>
|
|
|
|
/// </summary>
|
|
|
|
public static class EvolutionVerifier
|
2017-05-28 04:17:53 +00:00
|
|
|
{
|
2017-07-30 19:31:17 +00:00
|
|
|
/// <summary>
|
2022-06-18 18:04:24 +00:00
|
|
|
/// Verifies Evolution scenarios of an <see cref="IEncounterable"/> for an input <see cref="PKM"/> and relevant <see cref="LegalInfo"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="pk">Source data to verify</param>
|
|
|
|
/// <param name="info">Source supporting information to verify with</param>
|
|
|
|
public static CheckResult VerifyEvolution(PKM pk, LegalInfo info)
|
|
|
|
{
|
|
|
|
// Check if basic evolution methods are satisfiable with this encounter.
|
|
|
|
if (!IsValidEvolution(pk, info))
|
|
|
|
return new CheckResult(Severity.Invalid, LEvoInvalid, CheckIdentifier.Evolution);
|
|
|
|
|
|
|
|
// Check if complex evolution methods are satisfiable with this encounter.
|
|
|
|
if (!IsValidEvolutionWithMove(pk, info))
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(LMoveEvoFCombination_0, ParseSettings.SpeciesStrings[pk.Species]), CheckIdentifier.Evolution);
|
|
|
|
|
|
|
|
return VALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static readonly CheckResult VALID = new(CheckIdentifier.Evolution);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Checks if the Evolution from the source <see cref="IEncounterable"/> is valid.
|
2017-07-30 19:31:17 +00:00
|
|
|
/// </summary>
|
2022-06-18 18:04:24 +00:00
|
|
|
/// <param name="pk">Source data to verify</param>
|
|
|
|
/// <param name="info">Source supporting information to verify with</param>
|
|
|
|
/// <returns>Evolution is valid or not</returns>
|
|
|
|
private static bool IsValidEvolution(PKM pk, LegalInfo info)
|
2017-05-28 04:17:53 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
var chains = info.EvoChainsAllGens;
|
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 (chains.Get(pk.Context).Length == 0)
|
2022-06-18 18:04:24 +00:00
|
|
|
return false; // Can't exist as current species
|
2018-06-23 04:40:41 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// OK if un-evolved from original encounter
|
2022-08-27 06:43:36 +00:00
|
|
|
ushort species = pk.Species;
|
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
|
|
|
var enc = info.EncounterMatch;
|
|
|
|
if (species == enc.Species) // never evolved
|
2017-06-07 03:10:05 +00:00
|
|
|
return true;
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
// Bigender->Fixed (non-Genderless) destination species, accounting for PID-Gender relationship
|
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 (species == (int)Species.Vespiquen && enc.Generation < 6 && (pk.EncryptionConstant & 0xFF) >= 0x1F) // Combee->Vespiquen Invalid Evolution
|
2022-06-18 18:04:24 +00:00
|
|
|
return false;
|
|
|
|
|
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
|
|
|
// Double check that our encounter was able to exist as the encounter species.
|
|
|
|
foreach (var z in chains.Get(enc.Context))
|
|
|
|
{
|
|
|
|
if (z.Species == enc.Species)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2017-05-28 04:17:53 +00:00
|
|
|
}
|
|
|
|
}
|