mirror of
https://github.com/kwsch/PKHeX
synced 2024-12-23 19:03:11 +00:00
137 lines
4.9 KiB
C#
137 lines
4.9 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
|
||
|
namespace PKHeX.Core;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Logic to verify the current <see cref="PKM.RelearnMoves"/>.
|
||
|
/// </summary>
|
||
|
public static class LearnVerifierRelearn
|
||
|
{
|
||
|
public static void Verify(Span<MoveResult> result, IEncounterTemplate enc, PKM pk)
|
||
|
{
|
||
|
if (ShouldNotHaveRelearnMoves(enc, pk))
|
||
|
VerifyRelearnNone(pk, result);
|
||
|
else if (enc is IRelearn {Relearn: int[] {Length: not 0} x})
|
||
|
VerifyRelearnSpecifiedMoveset(pk, x, result);
|
||
|
else if (enc is EncounterEgg e)
|
||
|
VerifyEggMoveset(e, result, pk.RelearnMoves);
|
||
|
else if (enc is EncounterSlot6AO { CanDexNav: true } z && pk.RelearnMove1 != 0)
|
||
|
VerifyRelearnDexNav(pk, result, z);
|
||
|
else if (enc is EncounterSlot8b { IsUnderground: true } u)
|
||
|
VerifyRelearnUnderground(pk, result, u);
|
||
|
else
|
||
|
VerifyRelearnNone(pk, result);
|
||
|
}
|
||
|
|
||
|
public static bool ShouldNotHaveRelearnMoves(IGeneration enc, PKM pk) => enc.Generation < 6 || pk.IsOriginalMovesetDeleted();
|
||
|
|
||
|
private static void VerifyRelearnSpecifiedMoveset(PKM pk, IReadOnlyList<int> required, Span<MoveResult> result)
|
||
|
{
|
||
|
for (int i = result.Length - 1; i >= 0; i--)
|
||
|
{
|
||
|
var current = pk.GetRelearnMove(i);
|
||
|
var expect = required[i];
|
||
|
result[i] = ParseExpect(current, expect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
private static MoveResult ParseExpect(int move, int expect = 0)
|
||
|
{
|
||
|
if (move != expect)
|
||
|
return MoveResult.Unobtainable(expect);
|
||
|
if (move == 0)
|
||
|
return MoveResult.Empty;
|
||
|
return MoveResult.Relearn;
|
||
|
}
|
||
|
|
||
|
private static void VerifyRelearnDexNav(PKM pk, Span<MoveResult> result, EncounterSlot6AO slot)
|
||
|
{
|
||
|
// All other relearn moves must be empty.
|
||
|
result[3] = ParseExpect(pk.RelearnMove4);
|
||
|
result[2] = ParseExpect(pk.RelearnMove3);
|
||
|
result[1] = ParseExpect(pk.RelearnMove2);
|
||
|
|
||
|
// DexNav Pokémon can have 1 random egg move as a relearn move.
|
||
|
result[0] = slot.CanBeDexNavMove(pk.RelearnMove1) ? MoveResult.Relearn : MoveResult.Unobtainable(); // DexNav
|
||
|
}
|
||
|
|
||
|
private static void VerifyRelearnUnderground(PKM pk, Span<MoveResult> result, EncounterSlot8b slot)
|
||
|
{
|
||
|
// All other relearn moves must be empty.
|
||
|
result[3] = ParseExpect(pk.RelearnMove4);
|
||
|
result[2] = ParseExpect(pk.RelearnMove3);
|
||
|
result[1] = ParseExpect(pk.RelearnMove2);
|
||
|
|
||
|
// Underground Pokémon can have 1 random egg move as a relearn move.
|
||
|
result[0] = slot.CanBeUndergroundMove(pk.RelearnMove1) ? MoveResult.Relearn : MoveResult.Unobtainable(); // Underground
|
||
|
}
|
||
|
|
||
|
private static void VerifyRelearnNone(PKM pk, Span<MoveResult> result)
|
||
|
{
|
||
|
// No relearn moves should be present.
|
||
|
result[3] = ParseExpect(pk.RelearnMove4);
|
||
|
result[2] = ParseExpect(pk.RelearnMove3);
|
||
|
result[1] = ParseExpect(pk.RelearnMove2);
|
||
|
result[0] = ParseExpect(pk.RelearnMove1);
|
||
|
}
|
||
|
|
||
|
internal static void VerifyEggMoveset(EncounterEgg e, Span<MoveResult> result, ReadOnlySpan<int> moves)
|
||
|
{
|
||
|
int gen = e.Generation;
|
||
|
Span<byte> origins = stackalloc byte[moves.Length];
|
||
|
var valid = MoveBreed.Validate(gen, e.Species, e.Form, e.Version, moves, origins);
|
||
|
if (valid)
|
||
|
{
|
||
|
for (int i = result.Length - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (moves[i] == 0)
|
||
|
result[i] = MoveResult.Empty;
|
||
|
else
|
||
|
result[i] = new(EggSourceUtil.GetSource(origins[i], gen));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Span<int> expected = stackalloc int[moves.Length];
|
||
|
_ = MoveBreed.GetExpectedMoves(moves, e, expected);
|
||
|
_ = MoveBreed.Validate(gen, e.Species, e.Form, e.Version, expected, origins);
|
||
|
for (int i = moves.Length - 1; i >= 0; i--)
|
||
|
{
|
||
|
var current = moves[i];
|
||
|
var expect = expected[i];
|
||
|
if (current != expect)
|
||
|
result[i] = MoveResult.Unobtainable(expect);
|
||
|
else if (current == 0)
|
||
|
result[i] = MoveResult.Empty;
|
||
|
else
|
||
|
result[i] = new(EggSourceUtil.GetSource(origins[i], gen));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var dupe = IsAnyMoveDuplicate(moves);
|
||
|
if (dupe != NO_DUPE)
|
||
|
result[dupe] = MoveResult.Duplicate;
|
||
|
}
|
||
|
|
||
|
private const int NO_DUPE = -1;
|
||
|
|
||
|
private static int IsAnyMoveDuplicate(ReadOnlySpan<int> move)
|
||
|
{
|
||
|
int m1 = move[0];
|
||
|
int m2 = move[1];
|
||
|
|
||
|
if (m1 != 0 && m1 == m2)
|
||
|
return 1;
|
||
|
int m3 = move[2];
|
||
|
if (m3 != 0 && (m1 == m3 || m2 == m3))
|
||
|
return 2;
|
||
|
int m4 = move[3];
|
||
|
if (m4 != 0 && (m1 == m4 || m2 == m4 || m3 == m4))
|
||
|
return 3;
|
||
|
return NO_DUPE;
|
||
|
}
|
||
|
}
|