mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-02 04:29:05 -05:00
Cross generation check moves
This commit is contained in:
@@ -385,5 +385,23 @@ private static int getSuggestedTransferLocation(PKM pkm)
|
||||
return 30001;
|
||||
return -1;
|
||||
}
|
||||
private static int[] getGenMovesCheckOrder(PKM pkm)
|
||||
{
|
||||
if (pkm.Format == 1)
|
||||
return new [] { 1, 2 };
|
||||
else if (pkm.Format == 2)
|
||||
return new [] { 2, 1 };
|
||||
else if (pkm.Format == 7 && pkm.VC1)
|
||||
return new [] { 7, 1 };
|
||||
else if (pkm.Format == 7 && pkm.VC2)
|
||||
return new [] { 7, 2, 1 };
|
||||
else
|
||||
{
|
||||
var order = new int[pkm.Format - pkm.GenNumber + 1];
|
||||
for (int i = 0; i < order.Length; i++)
|
||||
order[i] = pkm.Format - i;
|
||||
return order;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ public static string[] getLocalization(string[] existingLines = null)
|
||||
public static string V174 { get; set; } = "Learned by Move Tutor.";
|
||||
public static string V175 { get; set; } = "Special Non-Relearn Move.";
|
||||
public static string V177 { get; set; } = "Learned by Level-up.";
|
||||
public static string V330 { get; set; } = "Learned by Level-up in generation {0}.";
|
||||
public static string V331 { get; set; } = "Learned by TM/HM in generation {0}.";
|
||||
public static string V332 { get; set; } = "Learned by Move Tutor in generation {0}.";
|
||||
public static string V333 { get; set; } = "Event Egg Move.";
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -353,6 +357,12 @@ public static string[] getLocalization(string[] existingLines = null)
|
||||
public static string V327 {get; set;} = "Special ingame N's Sparkle flag should not be checked.";
|
||||
public static string V328 {get; set;} = "Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.";
|
||||
|
||||
public static string V334 {get; set;} = "Non-tradeback egg move. Incompatible with generation 1 exclusive moves.";
|
||||
public static string V335 {get; set;} = "Generation 1 exclusive move. Incompatible with Non-tradeback egg moves.";
|
||||
public static string V336 {get; set;} = "Egg Move. Incompatible with event egg moves.";
|
||||
public static string V337 {get; set;} = "Event Egg Move. Incompatible with normal egg moves.";
|
||||
public static string V338 {get; set;} = "Defog and whirpool. One of the two moves should have been removed before transfered to generation 5.";
|
||||
public static string V339 {get; set;} = "Generation {0} HM. Should have been removed before transfered to generation {1}.";
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@@ -2021,10 +2021,10 @@ private void verifyVersionEvolution()
|
||||
|
||||
private CheckResult[] verifyMoves(GameVersion game = GameVersion.Any)
|
||||
{
|
||||
var validLevelMoves = Legal.getValidMoves(pkm, EvoChainsAllGens, Tutor: false, Machine: false).ToArray();
|
||||
var validTMHM = Legal.getValidMoves(pkm, EvoChainsAllGens, LVL: false, Tutor: false, MoveReminder: false).ToArray();
|
||||
var validTutor = Legal.getValidMoves(pkm, EvoChainsAllGens, LVL: false, Machine: false, MoveReminder: false).ToArray();
|
||||
|
||||
var validLevelMoves = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, Tutor: false, Machine: false, RemoveTransferHM:false);
|
||||
var validTMHM = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, LVL: false, Tutor: false, MoveReminder: false, RemoveTransferHM: false);
|
||||
var validTutor = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, LVL: false, Machine: false, MoveReminder: false, RemoveTransferHM: false);
|
||||
Legal.RemoveFutureMoves(pkm, EvoChainsAllGens, ref validLevelMoves, ref validTMHM, ref validTutor);
|
||||
CheckResult[] res;
|
||||
int[] Moves = pkm.Moves;
|
||||
if (pkm.Species == 235) // Smeargle can have any move except a few
|
||||
@@ -2050,13 +2050,13 @@ private CheckResult[] parseMovesSketch(int[] Moves)
|
||||
: new CheckResult(CheckIdentifier.Move);
|
||||
return res;
|
||||
}
|
||||
private CheckResult[] parseMovesGetGift(int[] Moves, int[] validLevelMoves, int[] validTMHM, int[] validTutor)
|
||||
private CheckResult[] parseMovesGetGift(int[] Moves, int[][] validLevelMoves, int[][] validTMHM, int[][] validTutor)
|
||||
{
|
||||
int[] RelearnMoves = pkm.RelearnMoves;
|
||||
foreach (MysteryGift mg in EventGiftMatch)
|
||||
{
|
||||
int[] SpecialMoves = mg.Moves;
|
||||
CheckResult[] res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, new int[0]);
|
||||
CheckResult[] res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, new int[0], new int[0]);
|
||||
if (res.Any(r => !r.Valid))
|
||||
continue;
|
||||
|
||||
@@ -2067,18 +2067,19 @@ private CheckResult[] parseMovesGetGift(int[] Moves, int[] validLevelMoves, int[
|
||||
}
|
||||
|
||||
// no Mystery Gifts matched
|
||||
return parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, new int[0], new int[0]);
|
||||
return parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, new int[0], new int[0], new int[0]);
|
||||
}
|
||||
private CheckResult[] parseMovesRegular(int[] Moves, int[] validLevelMoves, int[] validTMHM, int[] validTutor, GameVersion game)
|
||||
private CheckResult[] parseMovesRegular(int[] Moves, int[][] validLevelMoves, int[][] validTMHM, int[][] validTutor, GameVersion game)
|
||||
{
|
||||
int[] EggMoves = pkm.WasEgg ? Legal.getEggMoves(pkm, game).ToArray() : new int[0];
|
||||
int[] EventEggMoves = new int[0];
|
||||
int[] RelearnMoves = pkm.RelearnMoves;
|
||||
int[] SpecialMoves = (EncounterMatch as MysteryGift)?.Moves ??
|
||||
(EncounterMatch as EncounterStatic)?.Moves ??
|
||||
(EncounterMatch as EncounterTrade)?.Moves ??
|
||||
new int[0];
|
||||
|
||||
CheckResult[] res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, EggMoves);
|
||||
CheckResult[] res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, EggMoves, EventEggMoves);
|
||||
|
||||
if (pkm.GenNumber < 6)
|
||||
return res;
|
||||
@@ -2089,31 +2090,170 @@ private CheckResult[] parseMovesRegular(int[] Moves, int[] validLevelMoves, int[
|
||||
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMoves(int[] moves, int[] learn, int[] relearn, int[] tmhm, int[] tutor, int[] special, int[] egg)
|
||||
private CheckResult[] parseMoves(int[] moves, int[][] learn, int[] relearn, int[][] tmhm, int[][] tutor, int[] special, int[] egg, int[] eventegg)
|
||||
{
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
var Gen1MovesLearned = new List<int>();
|
||||
var EggMovesLearned = new List<int>();
|
||||
var EventEggMovesLearned = new List<int>();
|
||||
// Check none moves and relearn moves before generation moves
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (moves[i] == 0)
|
||||
res[i] = new CheckResult(Severity.Valid, V167, CheckIdentifier.Move);
|
||||
else if (learn.Contains(moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V177, CheckIdentifier.Move);
|
||||
else if (egg.Contains(moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V171, CheckIdentifier.Move) { Flag = true };
|
||||
else if (relearn.Contains(moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V172, CheckIdentifier.Move) { Flag = true };
|
||||
else if (tmhm.Contains(moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V173, CheckIdentifier.Move);
|
||||
else if (tutor.Contains(moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V174, CheckIdentifier.Move);
|
||||
else if (special.Contains(moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V175, CheckIdentifier.Move);
|
||||
else
|
||||
res[i] = new CheckResult(Severity.Invalid, V176, CheckIdentifier.Move);
|
||||
if (moves[m] == 0)
|
||||
res[m] = new CheckResult(Severity.Valid, V167, CheckIdentifier.Move);
|
||||
else if (relearn.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, V172, CheckIdentifier.Move) { Flag = true };
|
||||
}
|
||||
|
||||
if (res.All(r => r.Valid))
|
||||
return res;
|
||||
|
||||
bool MixedGen1NonTradebackGen2= false;
|
||||
// Check moves going backwards, marking the move valid in the most current generation when it can be learned
|
||||
int[] generations = getGenMovesCheckOrder(pkm);
|
||||
for (int g = 0; g < generations.Length; g++)
|
||||
{
|
||||
var gen = generations[g];
|
||||
if (!pkm.InhabitedGeneration(gen))
|
||||
continue;
|
||||
|
||||
IEnumerable<int> HMLearned = new List<int>();
|
||||
// Check if pokemon knows HM moves from generation 3 and 4 but are not valid yet, that means it cant learn the HMs in future generations
|
||||
bool KnowDefogWhirlpool = false;
|
||||
if (gen == 4 && pkm.Format > 4)
|
||||
{
|
||||
HMLearned = moves.Where((m,i) => !(res[i]?.Valid ?? false) && Legal.HM_4_RemovePokeTransfer.Any(l => l == m)).Select((m, i) => i);
|
||||
// Defog and Whirlpool at the same time, also both can't be learned in future generations or else they will be valid
|
||||
KnowDefogWhirlpool = moves.Where((m, i) => (m == 250 && m == 432) && !(res[i]?.Valid ?? false)).Count() == 2;
|
||||
}
|
||||
else if (gen == 3 && pkm.Format > 3)
|
||||
HMLearned = moves.Where((m, i) => !(res[i]?.Valid ?? false) && Legal.HM_3.Any(l => l == m)).Select((m, i) => i);
|
||||
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (res[m]?.Valid ?? false)
|
||||
continue;
|
||||
|
||||
if (learn[m].Contains(moves[m]))
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Valid, (gen == pkm.Format)? V177 : String.Format(V330, gen), CheckIdentifier.Move);
|
||||
if (gen == 1) Gen1MovesLearned.Add(m);
|
||||
}
|
||||
else if (tmhm[m].Contains(moves[m]))
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Valid, (gen == pkm.Format) ? V173 : String.Format(V331, gen), CheckIdentifier.Move);
|
||||
if (gen == 1) Gen1MovesLearned.Add(m);
|
||||
}
|
||||
else if (tutor[m].Contains(moves[m]))
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Valid, (gen == pkm.Format) ? V173 : String.Format(V332, gen), CheckIdentifier.Move);
|
||||
if (gen == 1) Gen1MovesLearned.Add(m);
|
||||
}
|
||||
else if (gen == pkm.GenNumber && special.Contains(moves[m]))
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Valid, V175, CheckIdentifier.Move);
|
||||
if (gen == 1) Gen1MovesLearned.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
if (gen == generations.Length - 1)
|
||||
{
|
||||
// Check egg moves after all the generations and all the moves, every move that can be learned in another source should have preference
|
||||
// the moves that can only be learned from egg moves should in the future check if the move combinations can be breed in gens 2 to 5
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (res[m]?.Valid ?? false)
|
||||
continue;
|
||||
if (egg.Contains(moves[m]))
|
||||
{
|
||||
if (Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1)
|
||||
{
|
||||
// To learn exclusive generation 1 moves the pokemon was tradeback, but it can be trade to generation 1
|
||||
// without removing moves above MaxMoveID_1, egg moves above MaxMoveID_1 and gen 1 moves are incompatible
|
||||
res[m] = new CheckResult(Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true };
|
||||
MixedGen1NonTradebackGen2 = true;
|
||||
}
|
||||
else
|
||||
res[m] = new CheckResult(Severity.Valid, V171, CheckIdentifier.Move) { Flag = true };
|
||||
EggMovesLearned.Add(m);
|
||||
}
|
||||
if (eventegg.Contains(moves[m]))
|
||||
{
|
||||
if(!egg.Contains(moves[m]))
|
||||
{
|
||||
if (Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1)
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true };
|
||||
MixedGen1NonTradebackGen2 = true;
|
||||
}
|
||||
else
|
||||
res[m] = new CheckResult(Severity.Valid, V33, CheckIdentifier.Move) { Flag = true };
|
||||
}
|
||||
EventEggMovesLearned.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
// A pokemon could have normal egg moves and regular egg moves only if all the event egg moves are also regular egg moves
|
||||
if (!EggMovesLearned.All(e=> EventEggMovesLearned.Contains(e)))
|
||||
{
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (EventEggMovesLearned.Contains(m) && !EggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, V337, CheckIdentifier.Move);
|
||||
else if (!EventEggMovesLearned.Contains(m) && EggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, V336, CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (3 <= gen && gen <= 4 && gen > pkm.Format)
|
||||
{
|
||||
// After all the moves from the generations 3 and 4,
|
||||
// including egg moves if is the origin generation because some hidden moves are also special egg moves in gen 3
|
||||
// Check if the marked hidden moves that were invalid at the start are now marked as valid, that means
|
||||
// the hidden move was learned in gen 3 or 4 but was not removed when transfer to 4 or 5
|
||||
if (KnowDefogWhirlpool)
|
||||
KnowDefogWhirlpool = moves.Where((m,i) => (m == 250 && m == 432) && (res[i]?.Valid ?? false)).Count() == 2;
|
||||
|
||||
if (KnowDefogWhirlpool)
|
||||
{
|
||||
KnowDefogWhirlpool = moves.Where((m, i) => (m == 250 && m == 432) && (res[i]?.Valid ?? false)).Count() == 2;
|
||||
foreach (int index in moves.Where(m => (m == 250 && m == 432)).Select((move, index) => index))
|
||||
{
|
||||
res[index] = new CheckResult(Severity.Invalid, V338, CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (int hm in HMLearned.Where(l => res[l]?.Valid ?? false))
|
||||
{
|
||||
res[hm] = new CheckResult(Severity.Invalid, string.Format(V339,gen,gen+1), CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the gen 1 exclusive moves as illegal because the pokemon also have Non tradeback egg moves.
|
||||
if (MixedGen1NonTradebackGen2)
|
||||
{
|
||||
foreach (int m in Gen1MovesLearned)
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Invalid, V335, CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
|
||||
if (res.All(r => r.Valid))
|
||||
return res;
|
||||
}
|
||||
|
||||
if (res.All(r => r.Valid))
|
||||
return res;
|
||||
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (res[m] == null)
|
||||
res[m] = new CheckResult(Severity.Invalid, V176, CheckIdentifier.Move);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private CheckResult[] verifyRelearn()
|
||||
{
|
||||
RelearnBase = null;
|
||||
|
||||
@@ -548,6 +548,28 @@ private static EncounterArea[] getTables2(GameVersion Version)
|
||||
}
|
||||
|
||||
// Moves
|
||||
internal static void RemoveFutureMoves(PKM pkm, DexLevel[][] evoChains, ref int[][] validLevelMoves, ref int[][] validTMHM, ref int[][] validTutor)
|
||||
{
|
||||
IEnumerable<int> AllMoves = new List<int>();
|
||||
if (pkm.Format > 3)
|
||||
{
|
||||
for (int i = evoChains.Length - 1; i > 0; i--)
|
||||
{
|
||||
validLevelMoves[i] = validLevelMoves[i].Except(AllMoves).ToArray();
|
||||
validTMHM[i] = validTMHM[i].Except(AllMoves).ToArray();
|
||||
validTutor[i] = validTutor[i].Except(AllMoves).ToArray();
|
||||
AllMoves = AllMoves.Concat(validLevelMoves[i]).Concat(validTMHM[i]).Concat(validTutor[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int tradeback = (pkm.Format == 2) ? 1 : 2;
|
||||
var formatmoves = validLevelMoves[pkm.Format].Concat(validTMHM[pkm.Format]).Concat(validTutor[pkm.Format]);
|
||||
validLevelMoves[tradeback] = validLevelMoves[tradeback].Except(formatmoves).ToArray();
|
||||
validTMHM[tradeback] = validTMHM[tradeback].Except(formatmoves).ToArray();
|
||||
validTutor[tradeback] = validTutor[tradeback].Except(formatmoves).ToArray();
|
||||
}
|
||||
}
|
||||
internal static int[][] getValidMovesAllGens(PKM pkm, DexLevel[][] evoChains, bool LVL = true, bool Tutor = true, bool Machine = true, bool MoveReminder = true, bool RemoveTransferHM = true)
|
||||
{
|
||||
int[][] Moves = new int[evoChains.Length][];
|
||||
|
||||
@@ -15,6 +15,9 @@ V173 = Learned by TM/HM.
|
||||
V174 = Learned by Move Tutor.
|
||||
V175 = Special Non-Relearn Move.
|
||||
V177 = Learned by Level-up.
|
||||
V330 = Learned by Level-up in generation {0}.
|
||||
V332 = Learned by Move Tutor in generation {0}.
|
||||
V333 = Event Egg Move.
|
||||
V203 = Genderless Pokémon should not have a gender.
|
||||
V201 = Encryption Constant is not set.
|
||||
V204 = Held item is unreleased.
|
||||
@@ -245,4 +248,10 @@ V324 = Special ingame Fateful Encounter flag missing.
|
||||
V325 = Fateful Encounter should not be checked.
|
||||
V326 = Special ingame N's Sparkle flag missing.
|
||||
V327 = Special ingame N's Sparkle flag should not be checked.
|
||||
V328 = Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.
|
||||
V328 = Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.
|
||||
V334 = Non-tradeback egg move. Incompatible with generation 1 exclusive moves.
|
||||
V335 = Generation 1 exclusive move. Incompatible with Non-tradeback egg moves.
|
||||
V336 = Egg Move. Incompatible with event egg moves.
|
||||
V337 = Event Egg Move. Incompatible with normal egg moves.
|
||||
V338 = Defog and whirpool. One of the two moves should have been removed before transfered to generation 5.
|
||||
V339 = Generation {0} HM. Should have been removed before transfered to generation {1}.
|
||||
Reference in New Issue
Block a user