PKHeX/PKHeX.Core/Editing/Applicators/MoveSetApplicator.cs
Kurt 0626b0c29b
Add Breeding move ordering logic, and use in legality analysis (#3183)
* Initial bred moveset validation logic

Unpeel the inheritance via recursion and permitted moves

* Volt tackle considerations

* Optimize out empty slot skips

* Add tests, fix off-by-one's

* Require all base moves if empty slot in moveset

* Add test to prove failure per Anubis' provided test

* Tweak enum labels for easier debugging

When two enums share the same underlying value, the ToString/name of the value may be either of the two (or the last defined one, in my debugging). Just give it a separate magic value.

* Fix recursion oopsie

Also check for scenario where no-base-moves but not enough moves to push base moves out

* Add Crystal tutor checks

* Add specialized gen2 verification method

Game loops through father's moves and pushes in one iteration, rather than checking by type.

* Add another case with returning base move

* Add push-out requirement for re-added base moves

* Minor tweaks

Condense tests, fix another off-by-one noticed when creating tests

* Disallow inherited parent levelup moves

Disallow volt tackle on Gen2/R/S

* Split MoveBreed into generation specific classes

Gen2 behaves slightly different from Gen3/4, which behaves slightly different from Gen5... and Gen6 behaves differently too.

Add some xmldoc as the api is starting to solidify

* Add method overload that returns the parse

Verify that the parse order is as expected

* Add reordering suggestion logic

Try sorting first, then go nuclear with rebuilding.

* Return base moves if complete fail

* Set base moves when generating eggs, only.

* Use breed logic to check for egg ordering legality

Don't bother helping for split-breed species
2021-04-04 18:30:01 -07:00

101 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{
public static class MoveSetApplicator
{
/// <summary>
/// Gets a moveset for the provided <see cref="PKM"/> data.
/// </summary>
/// <param name="pk">PKM to generate for</param>
/// <param name="random">Full movepool &amp; shuffling</param>
/// <returns>4 moves</returns>
public static int[] GetMoveSet(this PKM pk, bool random = false)
{
var la = new LegalityAnalysis(pk);
var moves = la.GetMoveSet(random);
if (random)
return moves;
var clone = pk.Clone();
clone.SetMoves(moves);
clone.SetMaximumPPCurrent(moves);
var newLa = new LegalityAnalysis(clone);
// ReSharper disable once TailRecursiveCall
return newLa.Valid ? moves : GetMoveSet(pk, true);
}
/// <summary>
/// Gets a moveset for the provided <see cref="PKM"/> data.
/// </summary>
/// <param name="la">Precomputed optional</param>
/// <param name="random">Full movepool &amp; shuffling</param>
/// <returns>4 moves</returns>
public static int[] GetMoveSet(this LegalityAnalysis la, bool random = false)
{
int[] m = la.GetSuggestedCurrentMoves(random ? MoveSourceType.All : MoveSourceType.Encounter);
var learn = la.GetSuggestedMovesAndRelearn();
if (!m.All(z => learn.Contains(z)))
m = m.Intersect(learn).ToArray();
if (random && !la.pkm.IsEgg)
Util.Shuffle(m);
const int count = 4;
if (m.Length > count)
return m.SliceEnd(m.Length - count);
Array.Resize(ref m, count);
return m;
}
/// <summary>
/// Fetches <see cref="PKM.RelearnMoves"/> based on the provided <see cref="LegalityAnalysis"/>.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="enc">Encounter the relearn moves should be suggested for. If not provided, will try to detect it via legality analysis. </param>
/// <returns><see cref="PKM.RelearnMoves"/> best suited for the current <see cref="PKM"/> data.</returns>
public static IReadOnlyList<int> GetSuggestedRelearnMoves(this PKM pk, IEncounterable? enc = null) => GetSuggestedRelearnMoves(new LegalityAnalysis(pk), enc);
/// <summary>
/// Fetches <see cref="PKM.RelearnMoves"/> based on the provided <see cref="LegalityAnalysis"/>.
/// </summary>
/// <param name="legal"><see cref="LegalityAnalysis"/> which contains parsed information pertaining to legality.</param>
/// <param name="enc">Encounter the relearn moves should be suggested for. If not provided, will try to detect it via legality analysis. </param>
/// <returns><see cref="PKM.RelearnMoves"/> best suited for the current <see cref="PKM"/> data.</returns>
public static IReadOnlyList<int> GetSuggestedRelearnMoves(this LegalityAnalysis legal, IEncounterable? enc = null)
{
var m = legal.GetSuggestedRelearnMovesFromEncounter();
if (m.Any(z => z != 0))
return m;
enc ??= legal.EncounterMatch;
if (enc is MysteryGift or EncounterEgg)
return m;
if (enc is EncounterSlot6AO {CanDexNav: true} dn)
{
var moves = legal.Info.Moves;
for (int i = 0; i < moves.Length; i++)
{
if (moves[i].Valid)
continue;
var move = legal.pkm.GetMove(i);
if (dn.CanBeDexNavMove(move))
return new[] { move, 0, 0, 0 };
}
}
var encounter = EncounterSuggestion.GetSuggestedMetInfo(legal.pkm);
if (encounter is IRelearn r && r.Relearn.Count > 0)
return r.Relearn;
return m;
}
}
}