diff --git a/PKHeX.Core/Editing/CommonEdits.cs b/PKHeX.Core/Editing/CommonEdits.cs index 401245442..92a483fbb 100644 --- a/PKHeX.Core/Editing/CommonEdits.cs +++ b/PKHeX.Core/Editing/CommonEdits.cs @@ -106,7 +106,7 @@ public static void SetAbilityIndex(this PKM pk, int index) public static void SetRandomEC(this PKM pk) { int gen = pk.Generation; - if (2 < gen && gen < 6) + if (gen is 3 or 4 or 5) { pk.EncryptionConstant = pk.PID; return; diff --git a/PKHeX.Core/Editing/HiddenPower.cs b/PKHeX.Core/Editing/HiddenPower.cs index 2fa75d890..3af7c1007 100644 --- a/PKHeX.Core/Editing/HiddenPower.cs +++ b/PKHeX.Core/Editing/HiddenPower.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -48,6 +49,19 @@ public static int GetTypeGB(IReadOnlyList IVs) return ((atk & 3) << 2) | (def & 3); } + /// + /// Modifies the provided to have the requested for Generations 1 & 2 + /// + /// Hidden Power Type + /// Current IVs + /// True if the Hidden Power of the is obtained, with or without modifications + public static bool SetTypeGB(int hiddenPowerType, int[] IVs) + { + IVs[1] = (IVs[1] & ~3) | (hiddenPowerType >> 2); + IVs[2] = (IVs[2] & ~3) | (hiddenPowerType & 3); + return true; + } + /// /// Modifies the provided to have the requested . /// @@ -58,11 +72,7 @@ public static int GetTypeGB(IReadOnlyList IVs) public static bool SetIVsForType(int hiddenPowerType, int[] IVs, int format) { if (format <= 2) - { - IVs[1] = (IVs[1] & ~3) | (hiddenPowerType >> 2); - IVs[2] = (IVs[2] & ~3) | (hiddenPowerType & 3); - return true; - } + return SetTypeGB(hiddenPowerType, IVs); return SetIVsForType(hiddenPowerType, IVs); } @@ -74,7 +84,7 @@ public static bool SetIVsForType(int hiddenPowerType, int[] IVs, int format) /// True if the Hidden Power of the is obtained, with or without modifications public static bool SetIVsForType(int hpVal, int[] IVs) { - if (IVs.All(z => z == 31)) + if (Array.TrueForAll(IVs, z => z == 31)) { SetIVs(hpVal, IVs); // Get IVs return true; @@ -101,9 +111,9 @@ public static bool SetIVsForType(int hpVal, int[] IVs) var permutations = GetPermutations(flawless, flawless.Length); int flawedCount = 0; int[]? best = null; + int[] ivs = (int[])IVs.Clone(); foreach (var permute in permutations) { - var ivs = (int[])IVs.Clone(); foreach (var item in permute) { ivs[item] ^= 1; @@ -115,9 +125,11 @@ public static bool SetIVsForType(int hpVal, int[] IVs) break; // any further flaws are always worse flawedCount = ct; - best = ivs; + best = (int[])ivs.Clone(); break; // any further flaws are always worse } + // Restore IVs for another iteration + Array.Copy(IVs, 0, ivs, 0, ivs.Length); } return best; } @@ -158,7 +170,7 @@ public static int[] SetIVs(int type, int[] ivs, int format = PKX.Generation) /// These are just precomputed for fast modification. /// Individual Values (H/A/B/S/C/D) /// - public static readonly int[,] DefaultLowBits = + public static readonly byte[,] DefaultLowBits = { { 1, 1, 0, 0, 0, 0 }, // Fighting { 0, 0, 0, 1, 0, 0 }, // Flying diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs b/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs index bd7c43b6a..e654f0539 100644 --- a/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs +++ b/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs @@ -166,8 +166,9 @@ private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, IReadOnlyList cu : ParseMovesWasEggPreRelearn(pkm, currentMoves, info, e); } + // Not all games have a re-learner. Initial moves may not fill out all 4 slots. int gen = info.EncounterMatch.Generation; - if (gen <= 2 && (gen == 1 || (gen == 2 && !ParseSettings.AllowGen2MoveReminder(pkm)))) // fixed encounter moves without relearning + if (gen == 1 || (gen == 2 && !AllowGen2MoveReminder(pkm))) return ParseMovesGenGB(pkm, currentMoves, info); return ParseMovesSpecialMoveset(pkm, currentMoves, info); @@ -176,13 +177,13 @@ private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, IReadOnlyList cu private static CheckMoveResult[] ParseMovesGenGB(PKM pkm, IReadOnlyList currentMoves, LegalInfo info) { var res = new CheckMoveResult[4]; - var G1Encounter = info.EncounterMatch; + var enc = info.EncounterMatch; var InitialMoves = Array.Empty(); - var SpecialMoves = GetSpecialMoves(info.EncounterMatch); - var games = info.EncounterMatch.Generation == 1 ? GBRestrictions.GetGen1Versions(info) : GBRestrictions.GetGen2Versions(info, pkm.Korean); + var SpecialMoves = GetSpecialMoves(enc); + var games = enc.Generation == 1 ? GBRestrictions.GetGen1Versions(enc) : GBRestrictions.GetGen2Versions(enc, pkm.Korean); foreach (var ver in games) { - var VerInitialMoves = MoveLevelUp.GetEncounterMoves(G1Encounter.Species, 0, G1Encounter.LevelMin, ver); + var VerInitialMoves = MoveLevelUp.GetEncounterMoves(enc.Species, 0, enc.LevelMin, ver); if (VerInitialMoves.Intersect(InitialMoves).Count() == VerInitialMoves.Length) return res; @@ -546,22 +547,22 @@ private static IList GetIncompatibleRBYMoves(PKM pkm, IReadOnlyList cu { // Vaporeon in Yellow learns Mist and Haze at level 42, Mist can only be learned if it leveled up in the daycare // Vaporeon in Red/Blue learns Acid Armor at level 42 and level 47 in Yellow - case (int)Species.Vaporeon when pkm.CurrentLevel < 47 && currentMoves.Contains(151): + case (int)Species.Vaporeon when pkm.CurrentLevel < 47 && currentMoves.Contains((int)Move.AcidArmor): { var incompatible = new List(3); - if (currentMoves.Contains(54)) - incompatible.Add(54); - if (currentMoves.Contains(114)) - incompatible.Add(114); + if (currentMoves.Contains((int)Move.Mist)) + incompatible.Add((int)Move.Mist); + if (currentMoves.Contains((int)Move.Haze)) + incompatible.Add((int)Move.Haze); if (incompatible.Count != 0) - incompatible.Add(151); + incompatible.Add((int)Move.AcidArmor); return incompatible; } // Flareon in Yellow learns Smog at level 42 // Flareon in Red Blue learns Leer at level 42 and level 47 in Yellow - case (int)Species.Flareon when pkm.CurrentLevel < 47 && currentMoves.Contains(43) && currentMoves.Contains(123): - return new[] {43, 123}; + case (int)Species.Flareon when pkm.CurrentLevel < 47 && currentMoves.Contains((int)Move.Leer) && currentMoves.Contains((int)Move.Smog): + return new[] { (int)Move.Leer, (int)Move.Smog }; default: return Array.Empty(); } @@ -664,25 +665,25 @@ private static void ParseEvolutionLevelupMove(PKM pkm, IList re { case (int)Species.MrMime: // Mr. Mime (Mime Jr with Mimic) case (int)Species.Sudowoodo: // Sudowoodo (Bonsly with Mimic) - ValidMoves.Add(102); + ValidMoves.Add((int)Move.Mimic); break; case (int)Species.Ambipom: // Ambipom (Aipom with Double Hit) - ValidMoves.Add(458); + ValidMoves.Add((int)Move.DoubleHit); break; case (int)Species.Lickilicky: // Lickilicky (Lickitung with Rollout) - ValidMoves.Add(205); + ValidMoves.Add((int)Move.Rollout); break; case (int)Species.Tangrowth: // Tangrowth (Tangela with Ancient Power) case (int)Species.Yanmega: // Yanmega (Yanma with Ancient Power) case (int)Species.Mamoswine: // Mamoswine (Piloswine with Ancient Power) - ValidMoves.Add(246); + ValidMoves.Add((int)Move.AncientPower); break; case (int)Species.Sylveon: // Sylveon (Eevee with Fairy Move) // Add every fairy moves without checking if Eevee learn it or not; pokemon moves are determined legal before this function ValidMoves.AddRange(EvolutionRestrictions.FairyMoves); break; case (int)Species.Tsareena: // Tsareena (Steenee with Stomp) - ValidMoves.Add(023); + ValidMoves.Add((int)Move.Stomp); break; } diff --git a/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs b/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs index 9429aac63..e17479b28 100644 --- a/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs +++ b/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs @@ -20,123 +20,103 @@ public static bool IsMoveRequiredToEvolve(int species, int format, int gen) internal static readonly int[] BabyEvolutionWithMove = { - 122, // Mr. Mime (Mime Jr with Mimic) - 185, // Sudowoodo (Bonsly with Mimic) + (int)Species.MrMime, // (Mime Jr with Mimic) + (int)Species.Sudowoodo, // (Bonsly with Mimic) }; // List of species that evolve from a previous species having a move while leveling up internal static readonly int[] SpeciesEvolutionWithMove = { - 122, // Mr. Mime (Mime Jr with Mimic) - 185, // Sudowoodo (Bonsly with Mimic) - 424, // Ambipom (Aipom with Double Hit) - 463, // Lickilicky (Lickitung with Rollout) - 465, // Tangrowth (Tangela with Ancient Power) - 469, // Yanmega (Yamma with Ancient Power) - 473, // Mamoswine (Piloswine with Ancient Power) - 700, // Sylveon (Eevee with Fairy Move) - 763, // Tsareena (Steenee with Stomp) + (int)Species.MrMime, // Mr. Mime (Mime Jr with Mimic) + (int)Species.Sudowoodo, // Sudowoodo (Bonsly with Mimic) + (int)Species.Ambipom, // Ambipom (Aipom with Double Hit) + (int)Species.Lickilicky, // Lickilicky (Lickitung with Rollout) + (int)Species.Tangrowth, // Tangrowth (Tangela with Ancient Power) + (int)Species.Yanmega, // Yanmega (Yamma with Ancient Power) + (int)Species.Mamoswine, // Mamoswine (Piloswine with Ancient Power) + (int)Species.Sylveon, // Sylveon (Eevee with Fairy Move) + (int)Species.Tsareena, // Tsareena (Steenee with Stomp) (int)Species.Grapploct // (Clobbopus with Taunt) }; internal static readonly int[] FairyMoves = { - 186, // Sweet Kiss - 204, // Charm - 236, // Moonlight - 574, // Disarming Voice - 577, // Draining Kiss - 578, // Crafty Shield - 579, // Flower Shield - 581, // Misty Terrain - 583, // Play Rough - 584, // Fairy Wind - 585, // Moonblast - 587, // Fairy Lock - 597, // Aromatic Mist - 601, // Geomancy - 605, // Dazzling Gleam - 608, // Baby-Doll Eyes - 617, // Light of Ruin - 656, // Twinkle Tackle - 657, // Twinkle Tackle - 666, // Floral Healing - 698, // Guardian of Alola - 705, // Fleur Cannon - 717, // Nature's Madness - 726, // Let's Snuggle Forever - 740, // Sparkly Swirl - 767, // Max Starfall - 777, // Decorate - 789, // Spirit Break - 790, // Strange Steam - 802, // Misty Explosion + (int)Move.SweetKiss, + (int)Move.Charm, + (int)Move.Moonlight, + (int)Move.DisarmingVoice, + (int)Move.DrainingKiss, + (int)Move.CraftyShield, + (int)Move.FlowerShield, + (int)Move.MistyTerrain, + (int)Move.PlayRough, + (int)Move.FairyWind, + (int)Move.Moonblast, + (int)Move.FairyLock, + (int)Move.AromaticMist, + (int)Move.Geomancy, + (int)Move.DazzlingGleam, + (int)Move.BabyDollEyes, + (int)Move.LightofRuin, + (int)Move.TwinkleTackleP, + (int)Move.TwinkleTackleS, + (int)Move.FloralHealing, + (int)Move.GuardianofAlola, + (int)Move.FleurCannon, + (int)Move.NaturesMadness, + (int)Move.LetsSnuggleForever, + (int)Move.SparklySwirl, + (int)Move.MaxStarfall, + (int)Move.Decorate, + (int)Move.SpiritBreak, + (int)Move.StrangeSteam, + (int)Move.MistyExplosion, }; // Moves that trigger the evolution by move private static readonly int[][] MoveEvolutionWithMove = { - new [] { 102 }, // Mr. Mime (Mime Jr with Mimic) - new [] { 102 }, // Sudowoodo (Bonsly with Mimic) - new [] { 458 }, // Ambipom (Aipom with Double Hit) - new [] { 205 }, // Lickilicky (Lickitung with Rollout) - new [] { 246 }, // Tangrowth (Tangela with Ancient Power) - new [] { 246 }, // Yanmega (Yamma with Ancient Power) - new [] { 246 }, // Mamoswine (Piloswine with Ancient Power) + new [] { (int)Move.Mimic }, // Mr. Mime (Mime Jr with Mimic) + new [] { (int)Move.Mimic }, // Sudowoodo (Bonsly with Mimic) + new [] { (int)Move.DoubleHit }, // Ambipom (Aipom with Double Hit) + new [] { (int)Move.Rollout }, // Lickilicky (Lickitung with Rollout) + new [] { (int)Move.AncientPower }, // Tangrowth (Tangela with Ancient Power) + new [] { (int)Move.AncientPower }, // Yanmega (Yamma with Ancient Power) + new [] { (int)Move.AncientPower }, // Mamoswine (Piloswine with Ancient Power) FairyMoves, // Sylveon (Eevee with Fairy Move) - new [] { 023 }, // Tsareena (Steenee with Stomp) - new [] { 269 }, // Grapploct (Clobbopus with Taunt) + new [] { (int)Move.Stomp }, // Tsareena (Steenee with Stomp) + new [] { (int)Move.Taunt }, // Grapploct (Clobbopus with Taunt) }; // Min level for any species for every generation to learn the move for evolution by move // 0 means it cant be learned in that generation private static readonly int[][] MinLevelEvolutionWithMove = { - // Mr. Mime (Mime Jr with Mimic) - new [] { 0, 0, 0, 0, 18, 15, 15, 2, 2 }, - // Sudowoodo (Bonsly with Mimic) - new [] { 0, 0, 0, 0, 17, 17, 15, 2, 2 }, - // Ambipom (Aipom with Double Hit) - new [] { 0, 0, 0, 0, 32, 32, 32, 2, 2 }, - // Lickilicky (Lickitung with Rollout) - new [] { 0, 0, 2, 0, 2, 33, 33, 2, 2 }, - // Tangrowth (Tangela with Ancient Power) - new [] { 0, 0, 0, 0, 2, 36, 38, 2, 2 }, - // Yanmega (Yanma with Ancient Power) - new [] { 0, 0, 0, 0, 2, 33, 33, 2, 2 }, - // Mamoswine (Piloswine with Ancient Power) - new [] { 0, 0, 0, 0, 2, 2, 2, 2, 2 }, - // Sylveon (Eevee with Fairy Move) - new [] { 0, 0, 0, 0, 0, 29, 9, 2, 2 }, - // Tsareena (Steenee with Stomp) - new [] { 0, 0, 0, 0, 0, 0, 0, 2, 28 }, - // Grapploct (Clobbopus with Taunt) - new [] { 0, 0, 0, 0, 0, 0, 0, 0, 35 }, + new [] { 00, 00, 00, 00, 18, 15, 15, 02, 02 }, // Mr. Mime (Mime Jr with Mimic) + new [] { 00, 00, 00, 00, 17, 17, 15, 02, 02 }, // Sudowoodo (Bonsly with Mimic) + new [] { 00, 00, 00, 00, 32, 32, 32, 02, 02 }, // Ambipom (Aipom with Double Hit) + new [] { 00, 00, 02, 00, 02, 33, 33, 02, 02 }, // Lickilicky (Lickitung with Rollout) + new [] { 00, 00, 00, 00, 02, 36, 38, 02, 02 }, // Tangrowth (Tangela with Ancient Power) + new [] { 00, 00, 00, 00, 02, 33, 33, 02, 02 }, // Yanmega (Yanma with Ancient Power) + new [] { 00, 00, 00, 00, 02, 02, 02, 02, 02 }, // Mamoswine (Piloswine with Ancient Power) + new [] { 00, 00, 00, 00, 00, 29, 09, 02, 02 }, // Sylveon (Eevee with Fairy Move) + new [] { 00, 00, 00, 00, 00, 00, 00, 02, 28 }, // Tsareena (Steenee with Stomp) + new [] { 00, 00, 00, 00, 00, 00, 00, 00, 35 }, // Grapploct (Clobbopus with Taunt) }; // True -> the pokemon could hatch from an egg with the move for evolution as an egg move private static readonly bool[][] EggMoveEvolutionWithMove = { - // Mr. Mime (Mime Jr with Mimic) - new [] { false, false, false, false, true, true, true, true, true }, - // Sudowoodo (Bonsly with Mimic) - new [] { false, false, false, false, true, true, true, true, true }, - // Ambipom (Aipom with Double Hit) - new [] { false, false, false, false, true, true, true, true, true }, - // Lickilicky (Lickitung with Rollout) - new [] { false, false, true, false, true, true, true, true, true }, - // Tangrowth (Tangela with Ancient Power) - new [] { false, false, false, false, true, true, true, true, true }, - // Yanmega (Yanma with Ancient Power) - new [] { false, false, false, false, true, true, true, true, true }, - // Mamoswine (Piloswine with Ancient Power) - new [] { false, false, true, true, true, true, true, true, true }, - // Sylveon (Eevee with Fairy Move) - new [] { false, false, true, true, true, true, true, true, true }, - // Tsareena (Steenee with Stomp) - new [] { false, false, false, false, false, false, false, false, false }, - // Grapploct (Clobbopus with Taunt) - new [] { false, false, false, false, false, false, false, false, true }, + new [] { false, false, false, false, true, true, true, true, true }, // Mr. Mime (Mime Jr with Mimic) + new [] { false, false, false, false, true, true, true, true, true }, // Sudowoodo (Bonsly with Mimic) + new [] { false, false, false, false, true, true, true, true, true }, // Ambipom (Aipom with Double Hit) + new [] { false, false, true, false, true, true, true, true, true }, // Lickilicky (Lickitung with Rollout) + new [] { false, false, false, false, true, true, true, true, true }, // Tangrowth (Tangela with Ancient Power) + new [] { false, false, false, false, true, true, true, true, true }, // Yanmega (Yanma with Ancient Power) + new [] { false, false, true, true, true, true, true, true, true }, // Mamoswine (Piloswine with Ancient Power) + new [] { false, false, true, true, true, true, true, true, true }, // Sylveon (Eevee with Fairy Move) + new [] { false, false, false, false, false, false, false, false, false }, // Tsareena (Steenee with Stomp) + new [] { false, false, false, false, false, false, false, false, true }, // Grapploct (Clobbopus with Taunt) }; public static bool IsEvolutionValidWithMove(PKM pkm, LegalInfo info) diff --git a/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs b/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs index 5926f545f..3c55d6a67 100644 --- a/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs +++ b/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs @@ -4,6 +4,8 @@ using PKHeX.Core; using static PKHeX.Core.Legal; +using static PKHeX.Core.GameVersion; +using static PKHeX.Core.Species; namespace PKHeX { @@ -26,20 +28,35 @@ internal static class GBRestrictions private static readonly HashSet Stadium_GiftSpecies = new() { - 001, // Bulbasaur - 004, // Charmander - 007, // Squirtle - 054, // Psyduck (Amnesia) - 106, // Hitmonlee - 107, // Hitmonchan - 133, // Eevee - 138, // Omanyte - 140, // Kabuto + (int)Bulbasaur, + (int)Charmander, + (int)Squirtle, + (int)Psyduck, + (int)Hitmonlee, + (int)Hitmonchan, + (int)Eevee, + (int)Omanyte, + (int)Kabuto, }; private static readonly HashSet SpecialMinMoveSlots = new() { - 25, 26, 29, 30, 31, 32, 33, 34, 36, 38, 40, 59, 91, 103, 114, 121, + (int)Pikachu, + (int)Raichu, + (int)NidoranF, + (int)Nidorina, + (int)Nidoqueen, + (int)NidoranM, + (int)Nidorino, + (int)Nidoking, + (int)Clefable, + (int)Ninetales, + (int)Wigglytuff, + (int)Arcanine, + (int)Cloyster, + (int)Exeggutor, + (int)Tangela, + (int)Starmie, }; internal static bool TypeIDExists(int type) => Types_Gen1.Contains(type); @@ -49,17 +66,35 @@ internal static class GBRestrictions 0, 1, 2, 3, 4, 5, 7, 8, 20, 21, 22, 23, 24, 25, 26 }; + /// + /// Species that have a catch rate value that is different from their pre-evolutions, and cannot be obtained directly. + /// internal static readonly HashSet Species_NotAvailable_CatchRate = new() { - 12, 18, 31, 34, 38, 45, 53, 59, 62, 65, 68, 71, 78, 91, 103, 121 + (int)Butterfree, + (int)Pidgeot, + (int)Nidoqueen, + (int)Nidoking, + (int)Ninetales, + (int)Vileplume, + (int)Persian, + (int)Arcanine, + (int)Poliwrath, + (int)Alakazam, + (int)Machamp, + (int)Victreebel, + (int)Rapidash, + (int)Cloyster, + (int)Exeggutor, + (int)Starmie, }; internal static readonly HashSet Trade_Evolution1 = new() { - 064, - 067, - 075, - 093 + (int)Kadabra, + (int)Machoke, + (int)Graveler, + (int)Haunter, }; private static int[] GetMinLevelLearnMoveG1(int species, List moves) @@ -108,7 +143,7 @@ internal static void GetIncompatibleEvolutionMoves(PKM pkm, IReadOnlyList m { switch (pkm.Species) { - case (int)Species.Nidoking when moves.Contains(31) && moves.Contains(37): + case (int)Nidoking when moves.Contains(31) && moves.Contains(37): // Nidoking learns Thrash at level 23 // Nidorino learns Fury Attack at level 36, Nidoran♂ at level 30 // Other moves are either learned by Nidoran♂ up to level 23 or by TM @@ -117,7 +152,7 @@ internal static void GetIncompatibleEvolutionMoves(PKM pkm, IReadOnlyList m previousspecies = 33; return; - case (int)Species.Exeggutor when moves.Contains(23) && moves.Any(m => G1Exeggcute_IncompatibleMoves.Contains(m)): + case (int)Exeggutor when moves.Contains(23) && moves.Any(m => G1Exeggcute_IncompatibleMoves.Contains(m)): // Exeggutor learns Stomp at level 28 // Exeggcute learns Stun Spore at 32, PoisonPowder at 37 and Sleep Powder at 48 incompatible_current = new[] { 23 }; @@ -125,12 +160,12 @@ internal static void GetIncompatibleEvolutionMoves(PKM pkm, IReadOnlyList m previousspecies = 103; return; - case (int)Species.Vaporeon or (int)Species.Jolteon or (int)Species.Flareon: + case (int)Vaporeon or (int)Jolteon or (int)Flareon: incompatible_previous = new List(); incompatible_current = new List(); previousspecies = 133; - var ExclusiveMoves = GetExclusiveMovesG1((int)Species.Eevee, pkm.Species, tmhm, moves); - var EeveeLevels = GetMinLevelLearnMoveG1((int)Species.Eevee, ExclusiveMoves[0]); + var ExclusiveMoves = GetExclusiveMovesG1((int)Eevee, pkm.Species, tmhm, moves); + var EeveeLevels = GetMinLevelLearnMoveG1((int)Eevee, ExclusiveMoves[0]); var EvoLevels = GetMaxLevelLearnMoveG1(pkm.Species, ExclusiveMoves[1]); for (int i = 0; i < ExclusiveMoves[0].Count; i++) @@ -191,15 +226,15 @@ private static int GetRequiredMoveSlotsRegular(PKM pk, IReadOnlyList moves, int catch_rate = ((PK1)pk).Catch_Rate; // Caterpie and Metapod evolution lines have different count of possible slots available if captured in different evolutionary phases // Example: a level 7 caterpie evolved into metapod will have 3 learned moves, a captured metapod will have only 1 move - if ((species == (int)Species.Metapod || species == (int)Species.Butterfree) && catch_rate == 120) + if ((species == (int)Metapod || species == (int)Butterfree) && catch_rate == 120) { // Captured as Metapod without Caterpie moves return initialmoves.Union(learn[1]).Distinct().Count(lm => lm != 0 && !G1CaterpieMoves.Contains(lm)); // There is no valid Butterfree encounter in generation 1 games } - if ((species == (int)Species.Kakuna || species == (int)Species.Beedrill) && (catch_rate == 45 || catch_rate == 120)) + if ((species == (int)Kakuna || species == (int)Beedrill) && (catch_rate == 45 || catch_rate == 120)) { - if (species == (int)Species.Beedrill && catch_rate == 45) // Captured as Beedril without Weedle and Kakuna moves + if (species == (int)Beedrill && catch_rate == 45) // Captured as Beedril without Weedle and Kakuna moves return initialmoves.Union(learn[1]).Distinct().Count(lm => lm != 0 && !G1KakunaMoves.Contains(lm)); // Captured as Kakuna without Weedle moves @@ -214,13 +249,13 @@ private static int GetRequiredMoveSlotsRegular(PKM pk, IReadOnlyList moves, // Species that evolve and learn the 4th move as evolved species at a greater level than base species // The 4th move is included in the level up table set as a pre-evolution move, // it should be removed from the used slots count if is not the learn move - (int)Species.Pidgeotto => level < 21 && !moves.Contains(018), // Whirlwind - (int)Species.Sandslash => level < 27 && !moves.Contains(040), // Poison Sting - (int)Species.Parasect => level < 30 && !moves.Contains(147), // Spore - (int)Species.Golduck => level < 39 && !moves.Contains(093), // Confusion - (int)Species.Dewgong => level < 44 && !moves.Contains(156), // Rest - (int)Species.Weezing => level < 39 && !moves.Contains(108), // Smoke Screen - (int)Species.Haunter or (int) Species.Gengar => level < 29 && !moves.Contains(095), // Hypnosis + (int)Pidgeotto => level < 21 && !moves.Contains(018), // Whirlwind + (int)Sandslash => level < 27 && !moves.Contains(040), // Poison Sting + (int)Parasect => level < 30 && !moves.Contains(147), // Spore + (int)Golduck => level < 39 && !moves.Contains(093), // Confusion + (int)Dewgong => level < 44 && !moves.Contains(156), // Rest + (int)Weezing => level < 39 && !moves.Contains(108), // Smoke Screen + (int)Haunter or (int)Gengar => level < 29 && !moves.Contains(095), // Hypnosis _ => false, }; @@ -229,20 +264,20 @@ private static int GetRequiredMoveCountDecrement(PKM pk, IReadOnlyList move int usedslots = initialmoves.Union(learn[1]).Where(m => m != 0).Distinct().Count(); switch (pk.Species) { - case (int)Species.Venonat: // Venonat; ignore Venomoth (by the time Venonat evolves it will always have 4 moves) + case (int)Venonat: // Venonat; ignore Venomoth (by the time Venonat evolves it will always have 4 moves) if (pk.CurrentLevel >= 11 && !moves.Contains(48)) // Supersonic usedslots--; if (pk.CurrentLevel >= 19 && !moves.Contains(93)) // Confusion usedslots--; break; - case (int)Species.Kadabra or (int)Species.Alakazam: // Abra & Kadabra + case (int)Kadabra or (int)Alakazam: // Abra & Kadabra int catch_rate = ((PK1)pk).Catch_Rate; if (catch_rate != 100)// Initial Yellow Kadabra Kinesis (move 134) usedslots--; if (catch_rate == 200 && pk.CurrentLevel < 20) // Kadabra Disable, not learned until 20 if captured as Abra (move 50) usedslots--; break; - case (int)Species.Cubone or (int)Species.Marowak: // Cubone & Marowak + case (int)Cubone or (int)Marowak: // Cubone & Marowak if (!moves.Contains(39)) // Initial Yellow Tail Whip usedslots--; if (!moves.Contains(125)) // Initial Yellow Bone Club @@ -250,15 +285,15 @@ private static int GetRequiredMoveCountDecrement(PKM pk, IReadOnlyList move if (pk.Species == 105 && pk.CurrentLevel < 33 && !moves.Contains(116)) // Marowak evolved without Focus Energy usedslots--; break; - case (int)Species.Chansey: + case (int)Chansey: if (!moves.Contains(39)) // Yellow Initial Tail Whip usedslots--; if (!moves.Contains(3)) // Yellow Lvl 12 and Initial Red/Blue Double Slap usedslots--; break; - case (int)Species.Mankey when pk.CurrentLevel >= 9 && !moves.Contains(67): // Mankey (Low Kick) - case (int)Species.Pinsir when pk.CurrentLevel >= 21 && !moves.Contains(20): // Pinsir (Bind) - case (int)Species.Gyarados when pk.CurrentLevel < 32: // Gyarados + case (int)Mankey when pk.CurrentLevel >= 9 && !moves.Contains(67): // Mankey (Low Kick) + case (int)Pinsir when pk.CurrentLevel >= 21 && !moves.Contains(20): // Pinsir (Bind) + case (int)Gyarados when pk.CurrentLevel < 32: // Gyarados usedslots--; break; default: return usedslots; @@ -274,17 +309,17 @@ private static int GetRequiredMoveCountSpecial(PKM pk, IReadOnlyList moves, var mandatory = GetRequiredMoveCountLevel(pk); switch (pk.Species) { - case (int)Species.Exeggutor when pk.CurrentLevel >= 28: // Exeggutor + case (int)Exeggutor when pk.CurrentLevel >= 28: // Exeggutor // At level 28 learn different move if is a Exeggute or Exeggutor if (moves.Contains(73)) mandatory.Add(73); // Leech Seed level 28 Exeggute if (moves.Contains(23)) mandatory.Add(23); // Stomp level 28 Exeggutor break; - case (int)Species.Pikachu when pk.CurrentLevel >= 33: + case (int)Pikachu when pk.CurrentLevel >= 33: mandatory.Add(97); // Pikachu always learns Agility break; - case (int)Species.Tangela: + case (int)Tangela: mandatory.Add(132); // Tangela always has Constrict as Initial Move break; } @@ -300,12 +335,12 @@ private static List GetRequiredMoveCountLevel(PKM pk) int maxlevel = 1; int minlevel = 1; - if (species == (int)Species.Tangela) // Tangela moves before level 32 are different in RB vs Y + if (species == (int)Tangela) // Tangela moves before level 32 are different in RB vs Y { minlevel = 32; maxlevel = pk.CurrentLevel; } - else if ((int)Species.NidoranF <= species && species <= (int)Species.Nidoking && pk.CurrentLevel >= 8) + else if (species is >= (int)NidoranF and <= (int)Nidoking && pk.CurrentLevel >= 8) { maxlevel = 8; // Always learns a third move at level 8 } @@ -316,31 +351,31 @@ private static List GetRequiredMoveCountLevel(PKM pk) return MoveLevelUp.GetMovesLevelUp1(basespecies, 0, maxlevel, minlevel); } - internal static IEnumerable GetGen2Versions(LegalInfo Info, bool korean) + internal static IEnumerable GetGen2Versions(IEncounterable enc, bool korean) { - if (ParseSettings.AllowGen2Crystal(korean) && Info.Game.Contains(GameVersion.C)) - yield return GameVersion.C; - yield return GameVersion.GS; + if (ParseSettings.AllowGen2Crystal(korean) && enc.Version is C or GSC) + yield return C; + yield return GS; } - internal static IEnumerable GetGen1Versions(LegalInfo Info) + internal static IEnumerable GetGen1Versions(IEncounterable enc) { - if (Info.EncounterMatch.Species == (int)Species.Eevee && Info.Game == GameVersion.Stadium) + if (enc.Species == (int)Eevee && enc.Version == Stadium) { // Stadium Eevee; check for RB and yellow initial moves - yield return GameVersion.RB; - yield return GameVersion.YW; + yield return RB; + yield return YW; yield break; } - if (Info.Game == GameVersion.YW) + if (enc.Version == YW) { - yield return GameVersion.YW; + yield return YW; yield break; } // Any encounter marked with version RBY is for pokemon with the same moves and catch rate in RB and Y, // it is sufficient to check just RB's case - yield return GameVersion.RB; + yield return RB; } private static bool GetCatchRateMatchesPreEvolution(PKM pkm, int catch_rate, IEnumerable gen1) @@ -352,7 +387,7 @@ private static bool GetCatchRateMatchesPreEvolution(PKM pkm, int catch_rate, IEn // Dragonite's Catch Rate is different than Dragonair's in Yellow, but there is no Dragonite encounter. bool IsCatchRateRBY(IEnumerable ds) => ds.Any(s => catch_rate == PersonalTable.RB[s].CatchRate || (s != 149 && catch_rate == PersonalTable.Y[s].CatchRate)); // Krabby encounter trade special catch rate - bool IsCatchRateTrade() => catch_rate == 204 && (pkm.Species == (int)Species.Krabby || pkm.Species == (int)Species.Kingler); + bool IsCatchRateTrade() => catch_rate == 204 && (pkm.Species == (int)Krabby || pkm.Species == (int)Kingler); bool IsCatchRateStadium() => Stadium_GiftSpecies.Contains(pkm.Species) && Stadium_CatchRate.Contains(catch_rate); } @@ -429,28 +464,27 @@ private static TradebackType GetTradebackStatusRBY(PK1 pkm) internal static bool IsTradedKadabraG1(PKM pkm) { - if (pkm is not PK1 pk1 || pk1.Species != (int)Species.Kadabra) + if (pkm is not PK1 pk1 || pk1.Species != (int)Kadabra) return false; if (pk1.TradebackStatus == TradebackType.WasTradeback) return true; - if (ParseSettings.ActiveTrainer.Game == (int)GameVersion.Any) + if (ParseSettings.ActiveTrainer.Game == (int)Any) return false; - var IsYellow = ParseSettings.ActiveTrainer.Game == (int)GameVersion.YW; + var IsYellow = ParseSettings.ActiveTrainer.Game == (int)YW; if (pk1.TradebackStatus == TradebackType.Gen1_NotTradeback) { // If catch rate is Abra catch rate it wont trigger as invalid trade without evolution, it could be traded as Abra // Yellow Kadabra catch rate in Red/Blue game, must be Alakazam var table = IsYellow ? PersonalTable.RB : PersonalTable.Y; - if (pk1.Catch_Rate == table[(int)Species.Kadabra].CatchRate) + if (pk1.Catch_Rate == table[(int)Kadabra].CatchRate) return true; } if (IsYellow) return false; // Yellow only moves in Red/Blue game, must be Alakazam - var moves = pk1.Moves; - if (moves.Contains(134)) // Kinesis, yellow only move + if (pk1.HasMove((int)Move.Kinesis)) // Kinesis, yellow only move return true; - if (pk1.CurrentLevel < 20 && moves.Contains(50)) // Obtaining Disable below level 20 implies a yellow only move + if (pk1.CurrentLevel < 20 && pk1.HasMove((int)Move.Disable)) // Obtaining Disable below level 20 implies a yellow only move return true; return false; diff --git a/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs b/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs index ec8825154..55f51f7f2 100644 --- a/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs @@ -24,8 +24,7 @@ public override void Verify(LegalityAnalysis data) // Check for PID relationship to Gender & Nature if applicable int gen = data.Info.Generation; - - if (3 <= gen && gen <= 5) + if (gen is 3 or 4 or 5) { // Gender-PID & Nature-PID relationship check var result = IsValidGenderPID(data) ? GetValid(LPIDGenderMatch) : GetInvalid(LPIDGenderMismatch); diff --git a/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs b/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs index aea74b2b1..f689db64f 100644 --- a/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs @@ -125,7 +125,7 @@ private static void VerifyEC(LegalityAnalysis data) } // Gen3-5 => Gen6 have PID==EC with an edge case exception. - if (3 <= Info.Generation && Info.Generation <= 5) + if (Info.Generation is 3 or 4 or 5) { VerifyTransferEC(data); return; diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 057bf273c..7b9f6d5ab 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -491,12 +491,13 @@ public virtual int HPType get => 15 * HPBitValType / 63; set { - IV_HP = (IV_HP & ~1) + HiddenPower.DefaultLowBits[value, 0]; - IV_ATK = (IV_ATK & ~1) + HiddenPower.DefaultLowBits[value, 1]; - IV_DEF = (IV_DEF & ~1) + HiddenPower.DefaultLowBits[value, 2]; - IV_SPE = (IV_SPE & ~1) + HiddenPower.DefaultLowBits[value, 3]; - IV_SPA = (IV_SPA & ~1) + HiddenPower.DefaultLowBits[value, 4]; - IV_SPD = (IV_SPD & ~1) + HiddenPower.DefaultLowBits[value, 5]; + var dlb = HiddenPower.DefaultLowBits; + IV_HP = (IV_HP & ~1) + dlb[value, 0]; + IV_ATK = (IV_ATK & ~1) + dlb[value, 1]; + IV_DEF = (IV_DEF & ~1) + dlb[value, 2]; + IV_SPE = (IV_SPE & ~1) + dlb[value, 3]; + IV_SPA = (IV_SPA & ~1) + dlb[value, 4]; + IV_SPD = (IV_SPD & ~1) + dlb[value, 5]; } } @@ -591,7 +592,8 @@ public bool InhabitedGeneration(int generation, int species = -1) if (species < 0) species = Species; - if (Format == generation) + var format = Format; + if (format == generation) return true; if (!IsOriginValid) @@ -602,21 +604,21 @@ public bool InhabitedGeneration(int generation, int species = -1) return false; // Trade generation 1 -> 2 - if (Format == 2 && generation == 1 && !Gen2_NotTradeback) + if (format == 2 && generation == 1 && !Gen2_NotTradeback) return true; // Trade generation 2 -> 1 - if (Format == 1 && generation == 2 && !Gen1_NotTradeback) + if (format == 1 && generation == 2 && !Gen1_NotTradeback) return true; - if (Format < generation) + if (format < generation) return false; // Future int gen = Generation; return generation switch { - 1 => Format == 1 || VC, // species compat checked via sanity above - 2 => Format == 2 || VC, + 1 => format == 1 || VC, // species compat checked via sanity above + 2 => format == 2 || VC, 3 => Gen3, 4 => gen is >= 3 and <= 4, 5 => gen is >= 3 and <= 5,