mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-23 20:43:07 +00:00
ccf87242c1
struct implementing interface is boxed when passed to method that accepts interface (not generic method). Removes IDexLevel (no other inheritors but EvoCriteria) and uses the primitive the data is stored (array, not IReadOnlyList) for slightly better perf.
197 lines
8.3 KiB
C#
197 lines
8.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
public static class MoveListSuggest
|
|
{
|
|
private static int[] GetSuggestedMoves(PKM pkm, EvoCriteria[][] evoChains, MoveSourceType types, IEncounterTemplate enc)
|
|
{
|
|
if (pkm.IsEgg && pkm.Format <= 5) // pre relearn
|
|
return MoveList.GetBaseEggMoves(pkm, pkm.Species, 0, (GameVersion)pkm.Version, pkm.CurrentLevel);
|
|
|
|
if (types != MoveSourceType.None)
|
|
return GetValidMoves(pkm, evoChains, types).Skip(1).ToArray(); // skip move 0
|
|
|
|
// try to give current moves
|
|
if (enc.Generation <= 2)
|
|
{
|
|
var lvl = pkm.Format >= 7 ? pkm.Met_Level : pkm.CurrentLevel;
|
|
var ver = enc.Version;
|
|
return MoveLevelUp.GetEncounterMoves(enc.Species, 0, lvl, ver);
|
|
}
|
|
|
|
if (pkm.Species == enc.Species)
|
|
{
|
|
return MoveLevelUp.GetEncounterMoves(pkm.Species, pkm.Form, pkm.CurrentLevel, (GameVersion)pkm.Version);
|
|
}
|
|
|
|
return GetValidMoves(pkm, evoChains, types).Skip(1).ToArray(); // skip move 0
|
|
}
|
|
|
|
private static IEnumerable<int> GetValidMoves(PKM pkm, EvoCriteria[][] evoChains, MoveSourceType types = MoveSourceType.ExternalSources, bool RemoveTransferHM = true)
|
|
{
|
|
GameVersion version = (GameVersion)pkm.Version;
|
|
if (!pkm.IsMovesetRestricted())
|
|
version = GameVersion.Any;
|
|
return GetValidMoves(pkm, version, evoChains, types: types, RemoveTransferHM: RemoveTransferHM);
|
|
}
|
|
|
|
private static IEnumerable<int> GetValidMoves(PKM pkm, GameVersion version, EvoCriteria[][] evoChains, MoveSourceType types = MoveSourceType.Reminder, bool RemoveTransferHM = true)
|
|
{
|
|
var r = new List<int> { 0 };
|
|
if (types.HasFlagFast(MoveSourceType.RelearnMoves) && pkm.Format >= 6)
|
|
r.AddRange(pkm.RelearnMoves);
|
|
|
|
int start = pkm.Generation;
|
|
if (start < 0)
|
|
start = pkm.Format; // be generous instead of returning nothing
|
|
if (pkm is IBattleVersion b)
|
|
start = Math.Max(0, b.GetMinGeneration());
|
|
|
|
for (int generation = start; generation <= pkm.Format; generation++)
|
|
{
|
|
var chain = evoChains[generation];
|
|
if (chain.Length == 0)
|
|
continue;
|
|
r.AddRange(MoveList.GetValidMoves(pkm, version, chain, generation, types: types, RemoveTransferHM: RemoveTransferHM));
|
|
}
|
|
|
|
return r.Distinct();
|
|
}
|
|
|
|
private static IEnumerable<int> AllSuggestedMoves(this LegalityAnalysis analysis)
|
|
{
|
|
if (!analysis.Parsed)
|
|
return new int[4];
|
|
return analysis.GetSuggestedCurrentMoves();
|
|
}
|
|
|
|
private static IEnumerable<int> AllSuggestedRelearnMoves(this LegalityAnalysis analysis)
|
|
{
|
|
if (!analysis.Parsed)
|
|
return new int[4];
|
|
var pkm = analysis.pkm;
|
|
var enc = analysis.EncounterMatch;
|
|
return MoveList.GetValidRelearn(pkm, enc.Species, enc.Form, (GameVersion)pkm.Version).ToArray();
|
|
}
|
|
|
|
public static int[] GetSuggestedMovesAndRelearn(this LegalityAnalysis analysis)
|
|
{
|
|
if (!analysis.Parsed)
|
|
return new int[4];
|
|
return analysis.AllSuggestedMoves().Concat(analysis.AllSuggestedRelearnMoves()).ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets four moves which can be learned depending on the input arguments.
|
|
/// </summary>
|
|
/// <param name="analysis">Parse information to generate a moveset for.</param>
|
|
/// <param name="types">Allowed move sources for populating the result array</param>
|
|
public static int[] GetSuggestedCurrentMoves(this LegalityAnalysis analysis, MoveSourceType types = MoveSourceType.All)
|
|
{
|
|
if (!analysis.Parsed)
|
|
return new int[4];
|
|
var pkm = analysis.pkm;
|
|
if (pkm.IsEgg && pkm.Format >= 6)
|
|
return pkm.RelearnMoves;
|
|
|
|
if (pkm.IsEgg)
|
|
types = types.ClearNonEggSources();
|
|
|
|
var info = analysis.Info;
|
|
return GetSuggestedMoves(pkm, info.EvoChainsAllGens, types, info.EncounterOriginal);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current <see cref="PKM.RelearnMoves"/> array of four moves that might be legal.
|
|
/// </summary>
|
|
/// <remarks>Use <see cref="GetSuggestedRelearnMovesFromEncounter"/> instead of calling directly; this method just puts default values in without considering the final moveset.</remarks>
|
|
public static IReadOnlyList<int> GetSuggestedRelearn(this IEncounterTemplate enc, PKM pkm)
|
|
{
|
|
if (VerifyRelearnMoves.ShouldNotHaveRelearnMoves(enc, pkm))
|
|
return Empty;
|
|
|
|
return GetSuggestedRelearnInternal(enc, pkm);
|
|
}
|
|
|
|
// Invalid encounters won't be recognized as an EncounterEgg; check if it *should* be a bred egg.
|
|
private static IReadOnlyList<int> GetSuggestedRelearnInternal(this IEncounterTemplate enc, PKM pkm) => enc switch
|
|
{
|
|
IRelearn s when s.Relearn.Count > 0 => s.Relearn,
|
|
EncounterEgg or EncounterInvalid {EggEncounter: true} => MoveBreed.GetExpectedMoves(pkm.RelearnMoves, enc),
|
|
_ => Empty,
|
|
};
|
|
|
|
private static readonly IReadOnlyList<int> Empty = new int[4];
|
|
|
|
/// <summary>
|
|
/// Gets the current <see cref="PKM.RelearnMoves"/> array of four moves that might be legal.
|
|
/// </summary>
|
|
public static IReadOnlyList<int> GetSuggestedRelearnMovesFromEncounter(this LegalityAnalysis analysis, IEncounterTemplate? enc = null)
|
|
{
|
|
var info = analysis.Info;
|
|
enc ??= info.EncounterOriginal;
|
|
var pkm = analysis.pkm;
|
|
|
|
if (VerifyRelearnMoves.ShouldNotHaveRelearnMoves(enc, pkm))
|
|
return Empty;
|
|
|
|
if (enc is EncounterEgg or EncounterInvalid {EggEncounter: true})
|
|
return enc.GetSuggestedRelearnEgg(info.Moves, pkm);
|
|
return enc.GetSuggestedRelearnInternal(pkm);
|
|
}
|
|
|
|
private static IReadOnlyList<int> GetSuggestedRelearnEgg(this IEncounterTemplate enc, IReadOnlyList<CheckMoveResult> parse, PKM pkm)
|
|
{
|
|
var result = enc.GetEggRelearnMoves(parse, pkm);
|
|
int generation = enc.Generation;
|
|
if (generation <= 5) // gen2 does not have splitbreed, <=5 do not have relearn moves and shouldn't even be here.
|
|
return result;
|
|
|
|
// Split-breed species like Budew & Roselia may be legal for one, and not the other.
|
|
// If we're not a split-breed or are already legal, return.
|
|
var split = Breeding.GetSplitBreedGeneration(generation);
|
|
if (!split.Contains(enc.Species))
|
|
return result;
|
|
|
|
var tmp = pkm.Clone();
|
|
tmp.SetRelearnMoves(result);
|
|
var la = new LegalityAnalysis(tmp);
|
|
if (la.Info.Moves.All(z => z.Valid))
|
|
return result;
|
|
|
|
// Try again with the other split-breed species if possible.
|
|
var incense = EncounterEggGenerator.GenerateEggs(tmp, generation).FirstOrDefault();
|
|
if (incense is null || incense.Species == enc.Species)
|
|
return result;
|
|
|
|
return incense.GetEggRelearnMoves(parse, pkm);
|
|
}
|
|
|
|
private static IReadOnlyList<int> GetEggRelearnMoves(this IEncounterTemplate enc, IReadOnlyList<CheckMoveResult> parse, PKM pkm)
|
|
{
|
|
// Extract a list of the moves that should end up in the relearn move list.
|
|
int ctr = 0;
|
|
var moves = new int[4];
|
|
for (var i = 0; i < parse.Count; i++)
|
|
{
|
|
var m = parse[i];
|
|
if (!m.ShouldBeInRelearnMoves())
|
|
continue;
|
|
moves[ctr++] = pkm.GetMove(i);
|
|
}
|
|
|
|
// Swap Volt Tackle to the end of the list.
|
|
int volt = Array.IndexOf(moves, (int) Move.VoltTackle, 0, ctr);
|
|
if (volt != -1)
|
|
{
|
|
var dest = ctr - 1;
|
|
moves[volt] = moves[dest];
|
|
moves[dest] = (int) Move.VoltTackle;
|
|
}
|
|
return MoveBreed.GetExpectedMoves(moves, enc);
|
|
}
|
|
}
|
|
}
|