mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-23 20:43:07 +00:00
cb24c20a44
Sure it's nice to cache a valid array, but the amount of logic was small enough that it can be done with 10 lines of code rather than at the end of each verification method. Reduces parameter passing & removes 1 field from the info object, as relearn suggestions are only done rarely after legality checking. Allows for a simpler api surface (pkm, encounter) rather than a bigger object reference
201 lines
9 KiB
C#
201 lines
9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
|
using static PKHeX.Core.LegalityAnalysis;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
/// <summary>
|
|
/// Logic to verify the current <see cref="PKM.RelearnMoves"/>.
|
|
/// </summary>
|
|
public static class VerifyRelearnMoves
|
|
{
|
|
public static CheckResult[] VerifyRelearn(PKM pkm, IEncounterable enc)
|
|
{
|
|
if (enc.Generation < 6 || (pkm is IBattleVersion v && v.BattleVersion != 0))
|
|
return VerifyRelearnNone(pkm);
|
|
|
|
return enc switch
|
|
{
|
|
IRelearn s when s.Relearn.Count > 0 => VerifyRelearnSpecifiedMoveset(pkm, s.Relearn),
|
|
EncounterEgg e => VerifyRelearnEggBase(pkm, e),
|
|
EncounterSlot6AO z when pkm.RelearnMove1 != 0 && z.CanDexNav => VerifyRelearnDexNav(pkm),
|
|
_ => VerifyRelearnNone(pkm)
|
|
};
|
|
}
|
|
|
|
public static IReadOnlyList<int> GetSuggestedRelearn(PKM pkm, IEncounterable enc, CheckResult[] relearn)
|
|
{
|
|
if (enc.Generation < 6 || (pkm is IBattleVersion v && v.BattleVersion != 0))
|
|
return Array.Empty<int>();
|
|
|
|
return enc switch
|
|
{
|
|
IRelearn s when s.Relearn.Count > 0 => s.Relearn,
|
|
EncounterEgg e => MoveList.GetBaseEggMoves(pkm, e.Species, e.Form, e.Version, e.Level),
|
|
EncounterSlot6AO z when pkm.RelearnMove1 != 0 && z.CanDexNav => relearn.All(r => r.Valid) ? pkm.RelearnMoves : Array.Empty<int>(),
|
|
_ => Array.Empty<int>(),
|
|
};
|
|
}
|
|
|
|
private static CheckResult[] VerifyRelearnSpecifiedMoveset(PKM pkm, IReadOnlyList<int> required)
|
|
{
|
|
CheckResult[] res = new CheckResult[4];
|
|
int[] relearn = pkm.RelearnMoves;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
res[i] = relearn[i] != required[i]
|
|
? new CheckResult(Severity.Invalid, string.Format(LMoveFExpect_0, MoveStrings[required[i]]), CheckIdentifier.RelearnMove)
|
|
: new CheckResult(CheckIdentifier.RelearnMove);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
private static CheckResult[] VerifyRelearnDexNav(PKM pkm)
|
|
{
|
|
var result = new CheckResult[4];
|
|
int[] relearn = pkm.RelearnMoves;
|
|
|
|
// DexNav Pokémon can have 1 random egg move as a relearn move.
|
|
var baseSpec = EvoBase.GetBaseSpecies(pkm);
|
|
result[0] = !MoveEgg.GetEggMoves(6, baseSpec.Species, baseSpec.Form, GameVersion.OR).Contains(relearn[0])
|
|
? new CheckResult(Severity.Invalid, LMoveRelearnDexNav, CheckIdentifier.RelearnMove)
|
|
: new CheckResult(CheckIdentifier.RelearnMove);
|
|
|
|
// All other relearn moves must be empty.
|
|
for (int i = 1; i < 4; i++)
|
|
{
|
|
result[i] = relearn[i] != 0
|
|
? new CheckResult(Severity.Invalid, LMoveRelearnNone, CheckIdentifier.RelearnMove)
|
|
: new CheckResult(CheckIdentifier.RelearnMove);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static CheckResult[] VerifyRelearnNone(PKM pkm)
|
|
{
|
|
var result = new CheckResult[4];
|
|
int[] RelearnMoves = pkm.RelearnMoves;
|
|
|
|
// No relearn moves should be present.
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
result[i] = RelearnMoves[i] != 0
|
|
? new CheckResult(Severity.Invalid, LMoveRelearnNone, CheckIdentifier.RelearnMove)
|
|
: new CheckResult(CheckIdentifier.RelearnMove);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static CheckResult[] VerifyRelearnEggBase(PKM pkm, EncounterEgg e)
|
|
{
|
|
int[] RelearnMoves = pkm.RelearnMoves;
|
|
var result = new CheckResult[4];
|
|
// Level up moves cannot be inherited if Ditto is the parent
|
|
// that means genderless species and male only species except Nidoran and Volbeat (they breed with female nidoran and illumise) could not have level up moves as an egg
|
|
bool inheritLvlMoves = Legal.GetCanInheritMoves(e.Species);
|
|
|
|
// Obtain level1 moves
|
|
var baseMoves = MoveList.GetBaseEggMoves(pkm, e.Species, e.Form, e.Version, 1);
|
|
int baseCt = Math.Min(4, baseMoves.Length);
|
|
|
|
// Obtain Inherited moves
|
|
var inheritMoves = MoveList.GetValidRelearn(pkm, e.Species, e.Form, inheritLvlMoves, e.Version).ToList();
|
|
int reqBase = GetRequiredBaseMoves(RelearnMoves, baseMoves, baseCt, inheritMoves);
|
|
|
|
// Check if the required amount of Base Egg Moves are present.
|
|
FlagBaseEggMoves(result, reqBase, baseMoves, RelearnMoves);
|
|
|
|
// Non-Base moves that can magically appear in the regular movepool
|
|
if (Legal.LightBall.Contains(pkm.Species))
|
|
inheritMoves.Add(344); // Volt Tackle
|
|
|
|
// If any splitbreed moves are invalid, flag accordingly
|
|
var splitMoves = e is EncounterEggSplit s
|
|
? MoveList.GetValidRelearn(pkm, s.OtherSpecies, s.Form, inheritLvlMoves, e.Version).ToList()
|
|
: (IReadOnlyList<int>)Array.Empty<int>();
|
|
|
|
// Inherited moves appear after the required base moves.
|
|
// If the pkm is capable of split-species breeding and any inherited move is from the other split scenario, flag accordingly.
|
|
bool splitInvalid = FlagInvalidInheritedMoves(result, reqBase, RelearnMoves, inheritMoves, splitMoves);
|
|
if (splitInvalid && e is EncounterEggSplit x)
|
|
FlagSplitbreedMoves(result, reqBase, x);
|
|
|
|
return result;
|
|
}
|
|
|
|
private static void FlagBaseEggMoves(CheckResult[] result, int required, IReadOnlyList<int> baseMoves, IReadOnlyList<int> RelearnMoves)
|
|
{
|
|
for (int i = 0; i < required; i++)
|
|
{
|
|
if (!baseMoves.Contains(RelearnMoves[i]))
|
|
{
|
|
FlagRelearnMovesMissing(result, required, baseMoves, i);
|
|
return;
|
|
}
|
|
result[i] = new CheckResult(Severity.Valid, LMoveRelearnEgg, CheckIdentifier.RelearnMove);
|
|
}
|
|
}
|
|
|
|
private static void FlagRelearnMovesMissing(CheckResult[] result, int required, IReadOnlyList<int> baseMoves, int start)
|
|
{
|
|
for (int z = start; z < required; z++)
|
|
result[z] = new CheckResult(Severity.Invalid, LMoveRelearnEggMissing, CheckIdentifier.RelearnMove);
|
|
|
|
// provide the list of suggested base moves for the last required slot
|
|
string em = string.Join(", ", GetMoveNames(baseMoves));
|
|
result[required - 1].Comment += string.Format(Environment.NewLine + LMoveRelearnFExpect_0, em);
|
|
}
|
|
|
|
private static bool FlagInvalidInheritedMoves(CheckResult[] result, int required, IReadOnlyList<int> RelearnMoves, IReadOnlyList<int> inheritMoves, IReadOnlyList<int> splitMoves)
|
|
{
|
|
bool splitInvalid = false;
|
|
bool isSplit = splitMoves.Count > 0;
|
|
for (int i = required; i < 4; i++)
|
|
{
|
|
if (RelearnMoves[i] == 0) // empty
|
|
result[i] = new CheckResult(Severity.Valid, LMoveSourceEmpty, CheckIdentifier.RelearnMove);
|
|
else if (inheritMoves.Contains(RelearnMoves[i])) // inherited
|
|
result[i] = new CheckResult(Severity.Valid, LMoveSourceRelearn, CheckIdentifier.RelearnMove);
|
|
else if (isSplit && splitMoves.Contains(RelearnMoves[i])) // inherited
|
|
splitInvalid = true;
|
|
else // not inheritable, flag
|
|
result[i] = new CheckResult(Severity.Invalid, LMoveRelearnInvalid, CheckIdentifier.RelearnMove);
|
|
}
|
|
|
|
return splitInvalid;
|
|
}
|
|
|
|
private static void FlagSplitbreedMoves(CheckResult[] res, int required, EncounterEggSplit x)
|
|
{
|
|
var other = x.OtherSpecies;
|
|
for (int i = required; i < 4; i++)
|
|
{
|
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
|
if (res[i] != null)
|
|
continue;
|
|
|
|
string message = string.Format(LMoveEggFIncompatible0_1, SpeciesStrings[other], SpeciesStrings[x.Species]);
|
|
res[i] = new CheckResult(Severity.Invalid, message, CheckIdentifier.RelearnMove);
|
|
}
|
|
}
|
|
|
|
private static int GetRequiredBaseMoves(int[] RelearnMoves, IReadOnlyList<int> baseMoves, int baseCt, IReadOnlyList<int> inheritMoves)
|
|
{
|
|
var inherited = RelearnMoves.Where(m => m != 0 && (!baseMoves.Contains(m) || inheritMoves.Contains(m))).ToList();
|
|
int inheritCt = inherited.Count;
|
|
|
|
// Get required amount of base moves
|
|
int unique = baseMoves.Union(inherited).Count();
|
|
int reqBase = inheritCt == 4 || baseCt + inheritCt > 4 ? 4 - inheritCt : baseCt;
|
|
if (RelearnMoves.Count(m => m != 0) < Math.Min(4, baseMoves.Count))
|
|
reqBase = Math.Min(4, unique);
|
|
return reqBase;
|
|
}
|
|
}
|
|
}
|