PKHeX/PKHeX.Core/Legality/Core.cs

489 lines
22 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{
public static partial class Legal
{
/// <summary> e-Reader Berry is Enigma or special berry </summary>
public static bool EReaderBerryIsEnigma { get; set; } = true;
/// <summary> e-Reader Berry Name </summary>
public static string EReaderBerryName { get; set; } = string.Empty;
/// <summary> e-Reader Berry Name formatted in Title Case </summary>
public static string EReaderBerryDisplayName => string.Format(LegalityCheckStrings.L_XEnigmaBerry_0, Util.ToTitleCase(EReaderBerryName.ToLower()));
// Gen 1
PKHeX.Core Nullable cleanup (#2401) * Handle some nullable cases Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data) Make some classes have explicit constructors instead of { } initialization * Handle bits more obviously without null * Make SaveFile.BAK explicitly readonly again * merge constructor methods to have readonly fields * Inline some properties * More nullable handling * Rearrange box actions define straightforward classes to not have any null properties * Make extrabyte reference array immutable * Move tooltip creation to designer * Rearrange some logic to reduce nesting * Cache generated fonts * Split mystery gift album purpose * Handle more tooltips * Disallow null setters * Don't capture RNG object, only type enum * Unify learnset objects Now have readonly properties which are never null don't new() empty learnsets (>800 Learnset objects no longer created, total of 2400 objects since we also new() a move & level array) optimize g1/2 reader for early abort case * Access rewrite Initialize blocks in a separate object, and get via that object removes a couple hundred "might be null" warnings since blocks are now readonly getters some block references have been relocated, but interfaces should expose all that's needed put HoF6 controls in a groupbox, and disable * Readonly personal data * IVs non nullable for mystery gift * Explicitly initialize forced encounter moves * Make shadow objects readonly & non-null Put murkrow fix in binary data resource, instead of on startup * Assign dex form fetch on constructor Fixes legality parsing edge cases also handle cxd parse for valid; exit before exception is thrown in FrameGenerator * Remove unnecessary null checks * Keep empty value until init SetPouch sets the value to an actual one during load, but whatever * Readonly team lock data * Readonly locks Put locked encounters at bottom (favor unlocked) * Mail readonly data / offset Rearrange some call flow and pass defaults Add fake classes for SaveDataEditor mocking Always party size, no need to check twice in stat editor use a fake save file as initial data for savedata editor, and for gamedata (wow i found a usage) constrain eventwork editor to struct variable types (uint, int, etc), thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
internal static readonly Learnset[] LevelUpRB = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), MaxSpeciesID_1);
internal static readonly Learnset[] LevelUpY = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), MaxSpeciesID_1);
2017-02-25 20:37:01 +00:00
// Gen 2
internal static readonly EggMoves[] EggMovesGS = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_gs.pkl"), MaxSpeciesID_2);
PKHeX.Core Nullable cleanup (#2401) * Handle some nullable cases Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data) Make some classes have explicit constructors instead of { } initialization * Handle bits more obviously without null * Make SaveFile.BAK explicitly readonly again * merge constructor methods to have readonly fields * Inline some properties * More nullable handling * Rearrange box actions define straightforward classes to not have any null properties * Make extrabyte reference array immutable * Move tooltip creation to designer * Rearrange some logic to reduce nesting * Cache generated fonts * Split mystery gift album purpose * Handle more tooltips * Disallow null setters * Don't capture RNG object, only type enum * Unify learnset objects Now have readonly properties which are never null don't new() empty learnsets (>800 Learnset objects no longer created, total of 2400 objects since we also new() a move & level array) optimize g1/2 reader for early abort case * Access rewrite Initialize blocks in a separate object, and get via that object removes a couple hundred "might be null" warnings since blocks are now readonly getters some block references have been relocated, but interfaces should expose all that's needed put HoF6 controls in a groupbox, and disable * Readonly personal data * IVs non nullable for mystery gift * Explicitly initialize forced encounter moves * Make shadow objects readonly & non-null Put murkrow fix in binary data resource, instead of on startup * Assign dex form fetch on constructor Fixes legality parsing edge cases also handle cxd parse for valid; exit before exception is thrown in FrameGenerator * Remove unnecessary null checks * Keep empty value until init SetPouch sets the value to an actual one during load, but whatever * Readonly team lock data * Readonly locks Put locked encounters at bottom (favor unlocked) * Mail readonly data / offset Rearrange some call flow and pass defaults Add fake classes for SaveDataEditor mocking Always party size, no need to check twice in stat editor use a fake save file as initial data for savedata editor, and for gamedata (wow i found a usage) constrain eventwork editor to struct variable types (uint, int, etc), thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
internal static readonly Learnset[] LevelUpGS = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), MaxSpeciesID_2);
internal static readonly EggMoves[] EggMovesC = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_c.pkl"), MaxSpeciesID_2);
PKHeX.Core Nullable cleanup (#2401) * Handle some nullable cases Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data) Make some classes have explicit constructors instead of { } initialization * Handle bits more obviously without null * Make SaveFile.BAK explicitly readonly again * merge constructor methods to have readonly fields * Inline some properties * More nullable handling * Rearrange box actions define straightforward classes to not have any null properties * Make extrabyte reference array immutable * Move tooltip creation to designer * Rearrange some logic to reduce nesting * Cache generated fonts * Split mystery gift album purpose * Handle more tooltips * Disallow null setters * Don't capture RNG object, only type enum * Unify learnset objects Now have readonly properties which are never null don't new() empty learnsets (>800 Learnset objects no longer created, total of 2400 objects since we also new() a move & level array) optimize g1/2 reader for early abort case * Access rewrite Initialize blocks in a separate object, and get via that object removes a couple hundred "might be null" warnings since blocks are now readonly getters some block references have been relocated, but interfaces should expose all that's needed put HoF6 controls in a groupbox, and disable * Readonly personal data * IVs non nullable for mystery gift * Explicitly initialize forced encounter moves * Make shadow objects readonly & non-null Put murkrow fix in binary data resource, instead of on startup * Assign dex form fetch on constructor Fixes legality parsing edge cases also handle cxd parse for valid; exit before exception is thrown in FrameGenerator * Remove unnecessary null checks * Keep empty value until init SetPouch sets the value to an actual one during load, but whatever * Readonly team lock data * Readonly locks Put locked encounters at bottom (favor unlocked) * Mail readonly data / offset Rearrange some call flow and pass defaults Add fake classes for SaveDataEditor mocking Always party size, no need to check twice in stat editor use a fake save file as initial data for savedata editor, and for gamedata (wow i found a usage) constrain eventwork editor to struct variable types (uint, int, etc), thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
internal static readonly Learnset[] LevelUpC = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2);
2017-02-25 20:37:01 +00:00
// Gen 3
2020-03-20 22:18:59 +00:00
internal static readonly Learnset[] LevelUpE = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_e.pkl"), "em"));
internal static readonly Learnset[] LevelUpRS = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs"));
internal static readonly Learnset[] LevelUpFR = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr"));
internal static readonly Learnset[] LevelUpLG = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg"));
internal static readonly EggMoves6[] EggMovesRS = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_rs.pkl"), "rs"));
// Gen 4
2020-03-20 22:18:59 +00:00
internal static readonly Learnset[] LevelUpDP = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp"));
internal static readonly Learnset[] LevelUpPt = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt"));
internal static readonly Learnset[] LevelUpHGSS = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs"));
internal static readonly EggMoves6[] EggMovesDPPt = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp"));
internal static readonly EggMoves6[] EggMovesHGSS = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs"));
// Gen 5
2020-03-20 22:18:59 +00:00
internal static readonly Learnset[] LevelUpBW = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_bw.pkl"), "51"));
internal static readonly Learnset[] LevelUpB2W2 = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52"));
internal static readonly EggMoves6[] EggMovesBW = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_bw.pkl"), "bw"));
// Gen 6
2020-03-20 22:18:59 +00:00
internal static readonly EggMoves6[] EggMovesXY = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_xy.pkl"), "xy"));
internal static readonly Learnset[] LevelUpXY = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy"));
internal static readonly EggMoves6[] EggMovesAO = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_ao.pkl"), "ao"));
internal static readonly Learnset[] LevelUpAO = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao"));
// Gen 7
2020-03-20 22:18:59 +00:00
internal static readonly EggMoves7[] EggMovesSM = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
internal static readonly Learnset[] LevelUpSM = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
internal static readonly EggMoves7[] EggMovesUSUM = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_uu.pkl"), "uu"));
internal static readonly Learnset[] LevelUpUSUM = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu"));
internal static readonly Learnset[] LevelUpGG = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg"));
// Gen 8
2020-03-20 22:18:59 +00:00
internal static readonly EggMoves7[] EggMovesSWSH = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_swsh.pkl"), "ss"));
internal static readonly Learnset[] LevelUpSWSH = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_swsh.pkl"), "ss"));
internal static bool GetCanBeEgg23(PKM pkm)
{
if (pkm.IsEgg)
return true;
if (pkm.Format > 2 && pkm.Ball != 4)
return false;
int lvl = pkm.CurrentLevel;
if (lvl < 5)
return false;
2017-09-04 20:48:10 +00:00
if (pkm.Format > 3 && pkm.Met_Level < 5)
return false;
if (pkm.Format > 3 && pkm.FatefulEncounter)
return false;
return IsEvolutionValid(pkm);
}
public static IReadOnlyList<byte> GetPPTable(PKM pkm, int format)
2018-11-14 03:10:31 +00:00
{
if (format != 7)
return GetPPTable(format);
return pkm.GG ? MovePP_GG : MovePP_SM;
2018-11-14 03:10:31 +00:00
}
public static IReadOnlyList<byte> GetPPTable(int format)
{
return format switch
{
1 => MovePP_RBY,
2 => MovePP_GSC,
3 => MovePP_RS,
4 => MovePP_DP,
5 => MovePP_BW,
6 => MovePP_XY,
7 => MovePP_SM,
8 => MovePP_SWSH,
_ => Array.Empty<byte>()
};
}
2020-05-31 19:12:48 +00:00
internal static ICollection<int> GetWildBalls(int gen, GameVersion game)
{
2020-05-31 19:12:48 +00:00
return gen switch
{
1 => WildPokeBalls1,
2 => WildPokeBalls2,
3 => WildPokeBalls3,
2020-05-31 19:12:48 +00:00
4 => GameVersion.HGSS.Contains(game) ? WildPokeBalls4_HGSS : WildPokeBalls4_DPPt,
5 => WildPokeBalls5,
6 => WildPokeballs6,
2020-05-31 19:12:48 +00:00
7 => GameVersion.GG.Contains(game) ? WildPokeballs7b : WildPokeballs7,
8 => WildPokeballs8,
2020-01-07 01:50:18 +00:00
_ => Array.Empty<int>()
};
}
internal static int GetEggHatchLevel(PKM pkm) => GetEggHatchLevel(pkm.Format);
internal static int GetEggHatchLevel(int gen) => gen <= 3 ? 5 : 1;
internal static ICollection<int> GetSplitBreedGeneration(int generation)
{
switch (generation)
{
case 3: return SplitBreed_3;
case 4:
case 5:
case 6:
case 7:
case 8:
return SplitBreed;
default: return Array.Empty<int>();
}
}
internal static int GetMaxSpeciesOrigin(PKM pkm)
{
if (pkm.Format == 1)
return GetMaxSpeciesOrigin(1);
if (pkm.Format == 2 || pkm.VC)
return GetMaxSpeciesOrigin(2);
return GetMaxSpeciesOrigin(pkm.GenNumber);
}
internal static int GetMaxSpeciesOrigin(int generation)
{
return generation switch
{
1 => MaxSpeciesID_1,
2 => MaxSpeciesID_2,
3 => MaxSpeciesID_3,
4 => MaxSpeciesID_4,
5 => MaxSpeciesID_5,
6 => MaxSpeciesID_6,
7 => MaxSpeciesID_7b,
8 => MaxSpeciesID_8,
_ => -1
};
}
internal static ICollection<int> GetFutureGenEvolutions(int generation)
{
return generation switch
{
1 => FutureEvolutionsGen1,
2 => FutureEvolutionsGen2,
3 => FutureEvolutionsGen3,
4 => FutureEvolutionsGen4,
5 => FutureEvolutionsGen5,
2020-01-07 01:50:18 +00:00
_ => Array.Empty<int>()
};
}
internal static int GetDebutGeneration(int species)
{
if (species <= MaxSpeciesID_1)
return 1;
if (species <= MaxSpeciesID_2)
return 2;
if (species <= MaxSpeciesID_3)
return 3;
if (species <= MaxSpeciesID_4)
return 4;
if (species <= MaxSpeciesID_5)
return 5;
if (species <= MaxSpeciesID_6)
return 6;
2018-11-14 03:10:31 +00:00
if (species <= MaxSpeciesID_7b)
return 7;
if (species <= MaxSpeciesID_8)
return 8;
return -1;
}
internal static int GetMaxLanguageID(int generation)
{
return generation switch
{
1 => (int) LanguageID.Spanish, // 1-7 except 6
3 => (int) LanguageID.Spanish, // 1-7 except 6
2 => (int) LanguageID.Korean,
4 => (int) LanguageID.Korean,
5 => (int) LanguageID.Korean,
6 => (int) LanguageID.Korean,
7 => (int) LanguageID.ChineseT,
8 => (int) LanguageID.ChineseT,
_ => -1
};
}
private static bool IsEvolvedFormChange(PKM pkm, int expected)
{
if (pkm.IsEgg)
return false;
if (pkm.Format >= 7 && (AlolanVariantEvolutions12.Contains(pkm.Species) || GalarVariantFormEvolutions.Contains(pkm.Species)))
return pkm.AltForm == 1;
2019-11-16 01:34:18 +00:00
if (pkm.Format >= 8)
{
if (GalarVariantFormEvolutions.Contains(pkm.Species))
return pkm.AltForm == 1;
if (GalarForm0Evolutions.TryGetValue(pkm.Species, out var orig))
return pkm.AltForm != orig; // bad compare?
if ((int) Species.Darmanitan == pkm.Species)
return pkm.AltForm == (expected == 1 ? 2 : 0);
if ((int) Species.MrMime == pkm.Species)
2020-04-24 15:24:12 +00:00
return pkm.AltForm == (expected == 0 ? 1 : 0);
if ((int) Species.Slowbro == pkm.Species)
return pkm.AltForm == (expected == 1 ? 2 : 0);
2019-11-18 06:04:41 +00:00
if ((int) Species.Toxtricity == pkm.Species)
return pkm.AltForm == EvolutionMethod.GetAmpLowKeyResult(pkm.Nature);
2019-12-29 02:59:00 +00:00
if ((int) Species.Alcremie == pkm.Species)
return true;
2019-11-16 01:34:18 +00:00
}
2019-11-18 06:04:41 +00:00
if ((pkm.Species == (int)Species.Meowstic || pkm.Species == (int)Species.Indeedee) && pkm.Gender == 1)
return pkm.AltForm == 1;
return pkm.Species == 773;
}
internal static bool IsEvolutionValid(PKM pkm, int minSpecies = -1, int minLevel = -1)
{
var curr = EvolutionChain.GetValidPreEvolutions(pkm, minLevel: minLevel);
var min = curr.FindLast(z => z.Species == minSpecies);
if (min != null && min.Level < minLevel)
return false;
var poss = EvolutionChain.GetValidPreEvolutions(pkm, lvl: 100, minLevel: minLevel, skipChecks: true);
if (minSpecies != -1)
{
int last = poss.FindLastIndex(z => z.Species == minSpecies);
return curr.Count >= last;
}
int gen = pkm.GenNumber;
if (gen >= 3 && GetSplitBreedGeneration(gen).Contains(EvoBase.GetBaseSpecies(poss, 1).Species))
return curr.Count >= poss.Count - 1;
return curr.Count >= poss.Count;
}
internal static bool IsEvolutionValidWithMove(PKM pkm, LegalInfo info)
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
{
// Exclude species that do not evolve leveling with a move
2017-06-07 03:52:21 +00:00
// Exclude gen 1-3 formats
// Exclude Mr. Mime and Snorlax for gen 1-3 games
var gen = info.Generation;
if (!SpeciesEvolutionWithMove.Contains(pkm.Species) || pkm.Format <= 3 || (BabyEvolutionWithMove.Contains(pkm.Species) && gen <= 3))
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
return true;
var index = Array.FindIndex(SpeciesEvolutionWithMove, p => p == pkm.Species);
var levels = MinLevelEvolutionWithMove[index];
var moves = MoveEvolutionWithMove[index];
var allowegg = EggMoveEvolutionWithMove[index][gen];
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
2017-06-07 03:52:21 +00:00
// Get the minimum level in any generation when the pokemon could learn the evolve move
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
var LearnLevel = 101;
for (int g = gen; g <= pkm.Format; g++)
{
2017-06-07 03:52:21 +00:00
if (pkm.InhabitedGeneration(g) && levels[g] > 0)
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
LearnLevel = Math.Min(LearnLevel, levels[g]);
}
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
// Check also if the current encounter include the evolve move as an special move
// That means the pokemon have the move from the encounter level
PKHeX.Core Nullable cleanup (#2401) * Handle some nullable cases Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data) Make some classes have explicit constructors instead of { } initialization * Handle bits more obviously without null * Make SaveFile.BAK explicitly readonly again * merge constructor methods to have readonly fields * Inline some properties * More nullable handling * Rearrange box actions define straightforward classes to not have any null properties * Make extrabyte reference array immutable * Move tooltip creation to designer * Rearrange some logic to reduce nesting * Cache generated fonts * Split mystery gift album purpose * Handle more tooltips * Disallow null setters * Don't capture RNG object, only type enum * Unify learnset objects Now have readonly properties which are never null don't new() empty learnsets (>800 Learnset objects no longer created, total of 2400 objects since we also new() a move & level array) optimize g1/2 reader for early abort case * Access rewrite Initialize blocks in a separate object, and get via that object removes a couple hundred "might be null" warnings since blocks are now readonly getters some block references have been relocated, but interfaces should expose all that's needed put HoF6 controls in a groupbox, and disable * Readonly personal data * IVs non nullable for mystery gift * Explicitly initialize forced encounter moves * Make shadow objects readonly & non-null Put murkrow fix in binary data resource, instead of on startup * Assign dex form fetch on constructor Fixes legality parsing edge cases also handle cxd parse for valid; exit before exception is thrown in FrameGenerator * Remove unnecessary null checks * Keep empty value until init SetPouch sets the value to an actual one during load, but whatever * Readonly team lock data * Readonly locks Put locked encounters at bottom (favor unlocked) * Mail readonly data / offset Rearrange some call flow and pass defaults Add fake classes for SaveDataEditor mocking Always party size, no need to check twice in stat editor use a fake save file as initial data for savedata editor, and for gamedata (wow i found a usage) constrain eventwork editor to struct variable types (uint, int, etc), thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
if (info.EncounterMatch is IMoveset s && s.Moves.Any(m => moves.Contains(m)))
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
LearnLevel = Math.Min(LearnLevel, info.EncounterMatch.LevelMin);
// If the encounter is a player hatched egg check if the move could be an egg move or inherited level up move
if (info.EncounterMatch.EggEncounter && !pkm.WasGiftEgg && !pkm.WasEventEgg && allowegg)
{
if (IsMoveInherited(pkm, info, moves))
LearnLevel = Math.Min(LearnLevel, gen <= 3 ? 6 : 2);
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
}
2017-06-07 03:52:21 +00:00
// If has original met location the minimum evolution level is one level after met level
// Gen 3 pokemon in gen 4 games: minimum level is one level after transfer to generation 4
// VC pokemon: minimum level is one level after transfer to generation 7
2018-05-12 15:13:39 +00:00
// Sylveon: always one level after met level, for gen 4 and 5 eevees in gen 6 games minimum for evolution is one level after transfer to generation 5
if (pkm.HasOriginalMetLocation || (pkm.Format == 4 && pkm.Gen3) || pkm.VC || pkm.Species == (int)Species.Sylveon)
LearnLevel = Math.Max(pkm.Met_Level + 1, LearnLevel);
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
// Current level must be at least one the minimum learn level
// the level-up event that triggers the learning of the move also triggers evolution with no further level-up required
return pkm.CurrentLevel >= LearnLevel;
New legallity checks (#1196) * Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
2017-06-07 03:10:05 +00:00
}
private static bool IsMoveInherited(PKM pkm, LegalInfo info, int[] moves)
2017-06-07 03:52:21 +00:00
{
// In 3DS games, the inherited move must be in the relearn moves.
if (info.Generation >= 6)
2017-06-07 03:52:21 +00:00
return pkm.RelearnMoves.Any(moves.Contains);
// In Pre-3DS games, the move is inherited if it has the move and it can be hatched with the move.
if (pkm.Moves.Any(moves.Contains))
return true;
// If the pokemon does not have the move, it still could be an egg move that was forgotten.
// This requires the pokemon to not have 4 other moves identified as egg moves or inherited level up moves.
return 4 > info.Moves.Count(m => m.Source == MoveSource.EggMove || m.Source == MoveSource.InheritLevelUp);
2017-06-07 03:52:21 +00:00
}
2019-12-29 02:59:00 +00:00
/// <summary>Checks if the form may be different than the original encounter detail.</summary>
/// <param name="pkm">Pokémon</param>
/// <param name="species">Original species</param>
/// <param name="form">Original form</param>
internal static bool IsFormChangeable(PKM pkm, int species, int form)
{
if (FormChange.Contains(species))
return true;
if (species != pkm.Species && IsEvolvedFormChange(pkm, form))
return true;
if (species == (int)Species.Zygarde && pkm.InhabitedGeneration(7) && pkm.AltForm > 1)
return true;
return false;
}
2018-05-12 15:13:39 +00:00
internal static bool GetCanInheritMoves(int species)
{
if (FixedGenderFromBiGender.Contains(species)) // Nincada -> Shedinja loses gender causing 'false', edge case
return true;
var pi = PKX.Personal[species];
if (!pi.Genderless && !pi.OnlyMale)
return true;
if (MixedGenderBreeding.Contains(species))
return true;
return false;
}
internal static bool GetCanLearnMachineMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any)
{
return MoveList.GetValidMoves(pkm, version, EvolutionChain.GetValidPreEvolutions(pkm), generation, Machine: true).Contains(move);
}
internal static bool GetCanRelearnMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any)
{
return MoveList.GetValidMoves(pkm, version, EvolutionChain.GetValidPreEvolutions(pkm), generation, LVL: true, Relearn: true).Contains(move);
}
internal static bool GetCanKnowMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any)
{
if (pkm.Species == (int)Species.Smeargle)
return !InvalidSketch.Contains(move);
return MoveList.GetValidMoves(pkm, version, EvolutionChain.GetValidPreEvolutions(pkm), generation, LVL: true, Relearn: true, Tutor: true, Machine: true).Contains(move);
}
private static int GetMaxLevelGeneration(PKM pkm)
{
return GetMaxLevelGeneration(pkm, pkm.GenNumber);
}
private static int GetMaxLevelGeneration(PKM pkm, int generation)
{
if (!pkm.InhabitedGeneration(generation))
return pkm.Met_Level;
if (pkm.Format <= 2)
{
if (generation == 1 && FutureEvolutionsGen1_Gen2LevelUp.Contains(pkm.Species))
return pkm.CurrentLevel - 1;
return pkm.CurrentLevel;
}
if (pkm.Species == (int)Species.Sylveon && generation == 5)
return pkm.CurrentLevel - 1;
2017-03-26 16:45:01 +00:00
if (pkm.Gen3 && pkm.Format > 4 && pkm.Met_Level == pkm.CurrentLevel && FutureEvolutionsGen3_LevelUpGen4.Contains(pkm.Species))
return pkm.Met_Level - 1;
if (!pkm.HasOriginalMetLocation)
return pkm.Met_Level;
2018-05-12 15:13:39 +00:00
return pkm.CurrentLevel;
}
internal static int GetMinLevelEncounter(PKM pkm)
{
// Only for gen 3 pokemon in format 3, after transfer to gen 4 it should return transfer level
if (pkm.Format == 3 && pkm.WasEgg)
return 5;
// Only for gen 4 pokemon in format 4, after transfer to gen 5 it should return transfer level
if (pkm.Format == 4 && pkm.Gen4 && pkm.WasEgg)
return 1;
return pkm.HasOriginalMetLocation ? pkm.Met_Level : GetMaxLevelGeneration(pkm);
}
internal static bool IsCatchRateHeldItem(int rate) => ParseSettings.AllowGen1Tradeback && HeldItems_GSC.Contains((ushort) rate);
2018-07-25 02:33:42 +00:00
internal const GameVersion NONE = GameVersion.Invalid;
internal static readonly LearnVersion LearnNONE = new LearnVersion(-1);
internal static bool HasVisitedB2W2(this PKM pkm) => pkm.InhabitedGeneration(5);
internal static bool HasVisitedORAS(this PKM pkm) => pkm.InhabitedGeneration(6) && (pkm.AO || !pkm.IsUntraded);
internal static bool HasVisitedUSUM(this PKM pkm) => pkm.InhabitedGeneration(7) && (pkm.USUM || !pkm.IsUntraded);
internal static bool IsMovesetRestricted(this PKM pkm, int gen) => (pkm.GG && gen == 7) || pkm.IsUntraded;
public static bool HasMetLocationUpdatedTransfer(int originalGeneration, int currentGeneration)
{
if (originalGeneration < 3)
return currentGeneration >= 3;
if (originalGeneration <= 4)
return currentGeneration != originalGeneration;
return false;
}
public static bool IsValidMissingLanguage(PKM pkm)
{
return pkm.Format == 5 && pkm.BW;
}
public static string GetG1OT_GFMew(int lang) => lang == (int)LanguageID.Japanese ? "ゲーフリ" : "GF";
public static string GetG5OT_NSparkle(int lang) => lang == (int)LanguageID.Japanese ? "" : "N";
public const string Stadium1JP = "スタジアム";
public static int GetGBStadiumOTID_JPN(GameVersion s)
{
return s == GameVersion.Stadium2 ? 2000 : 1999;
}
public static int GetMaxLengthOT(int gen, LanguageID lang)
{
switch (lang)
{
case LanguageID.Korean:
case LanguageID.Japanese: return gen >= 6 ? 6 : 5;
default: return gen >= 6 ? 12 : 7;
}
}
public static int GetMaxLengthNickname(int gen, LanguageID lang)
{
switch (lang)
{
case LanguageID.Korean:
case LanguageID.Japanese: return gen >= 6 ? 6 : 5;
default: return gen >= 6 ? 12 : 10;
}
}
2019-05-15 19:07:48 +00:00
public static bool GetIsFixedIVSequenceValidSkipRand(IReadOnlyList<int> IVs, PKM pkm, int max = 31)
{
for (int i = 0; i < 6; i++)
{
if ((uint) IVs[i] > max) // random
continue;
if (IVs[i] != pkm.GetIV(i))
return false;
}
return true;
}
public static bool GetIsFixedIVSequenceValidNoRand(IReadOnlyList<int> IVs, PKM pkm)
{
for (int i = 0; i < 6; i++)
{
if (IVs[i] != pkm.GetIV(i))
return false;
}
return true;
}
}
}