Add HOME hoopa move share, add form specific check

Hoopa cannot know both moves due to form reversion
Kyurem cannot know both moves due to form reversion
Kyurem cannot know Scary Face when fused in past games

Add dexnav for AtAnyTime/HOME lookback when original moveset deleted (no longer in local relearn moves)
BDSP Underground encounters w/ egg moves can be shared by other means
This commit is contained in:
Kurt 2023-07-15 13:58:41 -07:00
parent 18fd790657
commit 8c5773969a
7 changed files with 113 additions and 8 deletions

View file

@ -22,8 +22,13 @@ public sealed class LearnGroup6 : ILearnGroup
for (var i = 0; i < evos.Length; i++)
Check(result, current, pk, evos[i], i, types, option, mode);
if (option is not LearnOption.Current && types.HasFlag(MoveSourceType.Encounter) && enc is EncounterEgg { Generation: Generation } egg)
CheckEncounterMoves(result, current, egg);
if (option.IsPast() && types.HasFlag(MoveSourceType.Encounter))
{
if (enc is EncounterEgg { Generation: Generation } egg)
CheckEncounterMoves(result, current, egg);
else if (enc is EncounterSlot6AO { CanDexNav: true } dexnav && pk.IsOriginalMovesetDeleted())
CheckDexNavMoves(result, current, dexnav);
}
return MoveResult.AllParsed(result);
}
@ -48,6 +53,22 @@ public sealed class LearnGroup6 : ILearnGroup
}
}
private static void CheckDexNavMoves(Span<MoveResult> result, ReadOnlySpan<ushort> current, EncounterSlot6AO dexnav)
{
// DexNav moves are only available in OR/AS
// Can only have one DexNav move
for (var i = 0; i < result.Length; i++)
{
if (result[i].Valid)
continue;
var move = current[i];
if (!dexnav.CanBeDexNavMove(move))
continue;
result[i] = new(new(LearnMethod.Special, LearnEnvironment.ORAS), Generation);
break;
}
}
private static void Check(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk, EvoCriteria evo, int stage, MoveSourceType types, LearnOption option, CheckMode mode)
{
if (!FormChangeUtil.ShouldIterateForms(evo.Species, evo.Form, Generation, option))

View file

@ -29,7 +29,7 @@ public sealed class LearnGroup7 : ILearnGroup
for (var i = 0; i < evos.Length; i++)
Check(result, current, pk, evos[i], i, types, option, mode);
if (option is not LearnOption.Current && types.HasFlag(MoveSourceType.Encounter) && enc is EncounterEgg { Generation: Generation } egg)
if (option.IsPast() && types.HasFlag(MoveSourceType.Encounter) && enc is EncounterEgg { Generation: Generation } egg)
CheckEncounterMoves(result, current, egg);
return MoveResult.AllParsed(result);

View file

@ -46,7 +46,7 @@ public sealed class LearnGroup8 : ILearnGroup
CheckSharedMoves(result, current, evos[0]);
if (option is not LearnOption.Current && types.HasFlag(MoveSourceType.Encounter) && pk.IsOriginalMovesetDeleted() && enc is EncounterEgg { Generation: Generation } egg)
if (option.IsPast() && types.HasFlag(MoveSourceType.Encounter) && pk.IsOriginalMovesetDeleted() && enc is EncounterEgg { Generation: Generation } egg)
CheckEncounterMoves(result, current, egg);
if (MoveResult.AllParsed(result))

View file

@ -27,7 +27,7 @@ public sealed class LearnGroup9 : ILearnGroup
CheckSharedMoves(result, current, evos[0]);
if (option is not LearnOption.Current && types.HasFlag(MoveSourceType.Encounter) && pk.IsOriginalMovesetDeleted() && enc is EncounterEgg { Generation: Generation } egg)
if (option.IsPast() && types.HasFlag(MoveSourceType.Encounter) && pk.IsOriginalMovesetDeleted() && enc is EncounterEgg { Generation: Generation } egg)
CheckEncounterMoves(result, current, egg);
if (MoveResult.AllParsed(result))

View file

@ -60,6 +60,13 @@ public sealed class LearnGroupHOME : ILearnGroup
return true;
}
// HOME is silly and allows form exclusive moves to be transferred without ever knowing the move.
if (TryAddExclusiveMoves(result, current, pk))
{
if (CleanPurge(result, current, pk, types, local, evos))
return true;
}
// Ignore Battle Version; can be transferred back to SW/SH and wiped after the moves have been shared from HOME
if (history.HasVisitedLGPE)
@ -143,6 +150,7 @@ public sealed class LearnGroupHOME : ILearnGroup
if (history.HasVisitedBDSP && pk is not PB8)
RentLoopGetAll(LearnGroup8b.Instance, result, pk, history, enc, types, option, evos, local);
AddOriginalMoves(result, pk, enc, types, local, evos);
AddExclusiveMoves(result, pk);
// Looking backwards before HOME
if (history.HasVisitedLGPE)
@ -196,6 +204,31 @@ public sealed class LearnGroupHOME : ILearnGroup
}
}
private static bool TryAddExclusiveMoves(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk)
{
if (pk.Species is (int)Species.Hoopa)
{
var move = pk.Form == 0 ? (ushort)Move.HyperspaceHole : (ushort)Move.HyperspaceFury;
var index = current.IndexOf(move);
if (index < 0)
return false;
ref var exist = ref result[index];
if (exist.Valid)
return false;
exist = new MoveResult(new MoveLearnInfo(LearnMethod.Special, LearnEnvironment.HOME));
return true;
}
// Kyurem as Fused cannot move into HOME and trigger move sharing.
return false;
}
private static void AddExclusiveMoves(Span<bool> result, PKM pk)
{
if (pk.Species == (int)Species.Hoopa)
result[pk.Form == 0 ? (int)Move.HyperspaceHole : (int)Move.HyperspaceFury] = true;
}
/// <summary>
/// Get the current HOME source for the given context.
/// </summary>

View file

@ -29,9 +29,14 @@ internal static class LearnVerifier
private static void VerifyMoves(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk, IEncounterTemplate enc, EvolutionHistory history)
{
if (pk.IsEgg)
{
LearnVerifierEgg.Verify(result, current, enc, pk);
else
LearnVerifierHistory.Verify(result, current, enc, pk, history);
return;
}
LearnVerifierHistory.Verify(result, current, enc, pk, history);
// Check for form exclusive interlocked moves.
FlagFormExclusiveMoves(result, current, pk);
}
private static void Finalize(Span<MoveResult> result, ReadOnlySpan<ushort> current)
@ -89,4 +94,50 @@ internal static class LearnVerifier
result[i] = EmptyInvalid;
}
}
private static void FlagFormExclusiveMoves(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk)
{
if (pk is { Species: (int)Species.Hoopa })
FlagFormExclusiveHoopa(result, current, pk);
else if (pk is { Species: (int)Species.Kyurem })
FlagFormExclusiveKyurem(result, current, pk);
}
private static void FlagFormExclusiveHoopa(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk)
{
if (pk.Format < 8)
return;
// Hoopa in Gen8+ cannot have Hyperspace Hole if not form 0, and cannot have Hyperspace Fury if not form 1.
var disallow = pk.Form != 0 ? (ushort)Move.HyperspaceHole : (ushort)Move.HyperspaceFury;
var index = current.IndexOf(disallow);
if (index >= 0)
result[index] = MoveResult.Unobtainable(pk.Form == 0 ? (ushort)Move.HyperspaceHole : (ushort)Move.HyperspaceFury);
}
private static void FlagFormExclusiveKyurem(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk)
{
// Kyurem forms replace Scary Face with their Fusion Move and vice versa.
if (pk.Form is not 1) // not White
{
// Disallow Fusion Flare
var index = current.IndexOf((ushort)Move.FusionFlare);
if (index >= 0)
result[index] = MoveResult.Unobtainable((ushort)Move.ScaryFace);
}
if (pk.Form is not 2) // not Black
{
// Disallow Fusion Flare
var index = current.IndexOf((ushort)Move.FusionBolt);
if (index >= 0)
result[index] = MoveResult.Unobtainable((ushort)Move.ScaryFace);
}
if (pk.Form is not 0 && pk.Format < 8) // unfused
{
// Disallow Scary Face in formats < 8
var index = current.IndexOf((ushort)Move.ScaryFace);
if (index >= 0)
result[index] = MoveResult.Unobtainable(pk.Form == 1 ? (ushort)Move.FusionFlare : (ushort)Move.FusionBolt);
}
}
}

View file

@ -17,7 +17,7 @@ public static class FormChangeUtil
/// <param name="option">Conditions we're checking with</param>
public static bool ShouldIterateForms(ushort species, byte form, int generation, LearnOption option)
{
if (option is not LearnOption.Current)
if (option.IsPast())
return FormChangeMoves.TryGetValue(species, out var func) && func((generation, form));
return IterateAllForms(species);
}