diff --git a/PKHeX.Core/Legality/Areas/EncounterArea.cs b/PKHeX.Core/Legality/Areas/EncounterArea.cs index b1bfbe9b3..075028c21 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea.cs @@ -48,21 +48,21 @@ public static T[] GetSimpleEncounterArea(int[] species, int[] lvls, int locat /// Gets the slots contained in the area that match the provided data. /// /// Pokémon Data - /// Evolution lineage + /// Evolution lineage /// Minimum level of the encounter /// Enumerable list of encounters - public virtual IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyList vs, int minLevel = 0) + public virtual IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyList chain, int minLevel = 0) { if (minLevel == 0) // any - return Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species)); + return Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species)); - var slots = GetMatchFromEvoLevel(pkm, vs, minLevel); + var slots = GetMatchFromEvoLevel(pkm, chain, minLevel); return GetFilteredSlots(pkm, slots, minLevel); } - protected virtual IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected virtual IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { - var slots = Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); + var slots = Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); // Get slots where pokemon can exist with respect to level constraints return slots.Where(slot => slot.IsLevelWithinRange(minLevel)); } diff --git a/PKHeX.Core/Legality/Areas/EncounterArea3.cs b/PKHeX.Core/Legality/Areas/EncounterArea3.cs index d0df4761c..32fc41ecd 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea3.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea3.cs @@ -125,9 +125,9 @@ public static EncounterArea3[] GetArray3(byte[][] entries) return entries.Select(GetArea3).Where(Area => Area.Slots.Length != 0).ToArray(); } - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { - var slots = Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); + var slots = Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); if (pkm.Format != 3) // transferred to Gen4+ return slots.Where(slot => slot.LevelMin <= minLevel); diff --git a/PKHeX.Core/Legality/Areas/EncounterArea4.cs b/PKHeX.Core/Legality/Areas/EncounterArea4.cs index 1b3e32703..05856dfab 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea4.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea4.cs @@ -59,9 +59,9 @@ protected static void MarkStaticMagnetPermute(IEnumerable grp, Li EncounterUtil.MarkEncountersStaticMagnetPullPermutation(grp, PersonalTable.HGSS, trackPermute); } - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { - var slots = Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); + var slots = Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); if (pkm.Format != 4) // transferred to Gen5+ return slots.Where(slot => slot.LevelMin <= minLevel); diff --git a/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs b/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs index 59f967067..6fe53a148 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs @@ -13,9 +13,9 @@ public sealed class EncounterArea6AO : EncounterArea32 private const int FluteBoostMax = 4; // Black Flute increases levels. private const int DexNavBoost = 30; // Maximum DexNav chain - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { - var slots = Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species && evo.Level >= (slot.LevelMin - FluteBoostMax))); + var slots = Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species && evo.Level >= (slot.LevelMin - FluteBoostMax))); // note: it's probably possible to determine a reduced DexNav boost based on the flawless IV count (no flawless = not chained) // if someone wants to implement that logic to have the below method return a calculated max DexNavBoost, send a pull request :) diff --git a/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs b/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs index 9e15156d8..bb31a08f6 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs @@ -71,14 +71,14 @@ public static bool WasFriendSafari(PKM pkm) public static IEnumerable GetValidFriendSafari(PKM pkm) { - var vs = EvolutionChain.GetValidPreEvolutions(pkm); - return GetValidFriendSafari(vs); + var chain = EvolutionChain.GetValidPreEvolutions(pkm); + return GetValidFriendSafari(chain); } - public static IEnumerable GetValidFriendSafari(IEnumerable vs) + public static IEnumerable GetValidFriendSafari(IReadOnlyList chain) { - var evos = vs.Where(d => d.Level >= 30); - return evos.SelectMany(z => Encounters6.FriendSafari[z.Species]); + var valid = chain.Where(d => d.Level >= 30); + return valid.SelectMany(z => Encounters6.FriendSafari[z.Species]); } } } \ No newline at end of file diff --git a/PKHeX.Core/Legality/Areas/EncounterArea7b.cs b/PKHeX.Core/Legality/Areas/EncounterArea7b.cs index aab471b11..f51f12985 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea7b.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea7b.cs @@ -11,9 +11,9 @@ public sealed class EncounterArea7b : EncounterArea32 { private const int CatchComboBonus = 1; - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { - var slots = Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species && evo.Form == slot.Form && evo.Level >= (slot.LevelMin - CatchComboBonus))); + var slots = Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species && evo.Form == slot.Form && evo.Level >= (slot.LevelMin - CatchComboBonus))); // Get slots where pokemon can exist with respect to level constraints return slots.Where(s => s.IsLevelWithinRange(minLevel, minLevel, 0, CatchComboBonus)); diff --git a/PKHeX.Core/Legality/Areas/EncounterArea8.cs b/PKHeX.Core/Legality/Areas/EncounterArea8.cs index d0f0f6360..a00382447 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea8.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea8.cs @@ -27,7 +27,7 @@ public override bool IsMatchLocation(int location) return others.Contains((byte)location); } - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { var loc = Location; if (IsWildArea8(loc) || IsWildArea8Armor(loc)) // wild area gets boosted up to level 60 post-game @@ -35,11 +35,11 @@ protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnu const int boostTo = 60; if (pkm.Met_Level == boostTo) { - var boost = Slots.Where(slot => vs.Any(evo => IsMatch(evo, slot) && evo.Level >= boostTo)); + var boost = Slots.Where(slot => chain.Any(evo => IsMatch(evo, slot) && evo.Level >= boostTo)); return boost.Where(s => s.LevelMax < boostTo || s.IsLevelWithinRange(minLevel)); } } - var slots = Slots.Where(slot => vs.Any(evo => IsMatch(evo, slot) && evo.Level >= slot.LevelMin)); + var slots = Slots.Where(slot => chain.Any(evo => IsMatch(evo, slot) && evo.Level >= slot.LevelMin)); // Get slots where pokemon can exist with respect to level constraints return slots.Where(s => s.IsLevelWithinRange(minLevel)); diff --git a/PKHeX.Core/Legality/Areas/EncounterAreaFake.cs b/PKHeX.Core/Legality/Areas/EncounterAreaFake.cs index ad73c6002..74a4db144 100644 --- a/PKHeX.Core/Legality/Areas/EncounterAreaFake.cs +++ b/PKHeX.Core/Legality/Areas/EncounterAreaFake.cs @@ -9,7 +9,7 @@ namespace PKHeX.Core /// public sealed class EncounterAreaFake : EncounterArea { - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) => Enumerable.Empty(); protected override IEnumerable GetFilteredSlots(PKM pkm, IEnumerable slots, int minLevel) diff --git a/PKHeX.Core/Legality/Areas/EncounterAreaGB.cs b/PKHeX.Core/Legality/Areas/EncounterAreaGB.cs index dc48d0285..dc17840e3 100644 --- a/PKHeX.Core/Legality/Areas/EncounterAreaGB.cs +++ b/PKHeX.Core/Legality/Areas/EncounterAreaGB.cs @@ -39,22 +39,22 @@ protected static EncounterSlot1[] ReadSlots1(byte[] data, ref int ofs, int count return slots; } - public override IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyList vs, int minLevel = 0) + public override IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyList chain, int minLevel = 0) { if (minLevel == 0) // any - return Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species)); + return Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species)); var Gen1Version = GameVersion.RBY; bool RBDragonair = false; - if (minLevel != 0 && !FilterGBSlotsCatchRate(pkm, ref vs, ref Gen1Version, ref RBDragonair)) + if (minLevel != 0 && !FilterGBSlotsCatchRate(pkm, ref chain, ref Gen1Version, ref RBDragonair)) return Enumerable.Empty(); - var encounterSlots = GetMatchFromEvoLevel(pkm, vs, minLevel); + var encounterSlots = GetMatchFromEvoLevel(pkm, chain, minLevel); return GetFilteredSlots(pkm, encounterSlots, Gen1Version, RBDragonair).OrderBy(slot => slot.LevelMin); // prefer lowest levels } - private static bool FilterGBSlotsCatchRate(PKM pkm, ref IReadOnlyList vs, ref GameVersion Gen1Version, ref bool RBDragonair) + private static bool FilterGBSlotsCatchRate(PKM pkm, ref IReadOnlyList chain, ref GameVersion Gen1Version, ref bool RBDragonair) { if (!(pkm is PK1 pk1) || !pkm.Gen1_NotTradeback) return true; @@ -71,34 +71,34 @@ private static bool FilterGBSlotsCatchRate(PKM pkm, ref IReadOnlyList s.Species == (int)Species.Kadabra).ToArray(); + chain = chain.Where(s => s.Species == (int)Species.Kadabra).ToArray(); Gen1Version = GameVersion.YW; return true; // Kadabra (RB) case (int)Species.Kadabra when rate == 100: case (int)Species.Alakazam when rate == 100: - vs = vs.Where(s => s.Species == (int)Species.Kadabra).ToArray(); + chain = chain.Where(s => s.Species == (int)Species.Kadabra).ToArray(); Gen1Version = GameVersion.RB; return true; // Dragonair (YW) case (int)Species.Dragonair when rate == 27: case (int)Species.Dragonite when rate == 27: - vs = vs.Where(s => s.Species == (int)Species.Dragonair).ToArray(); // Yellow Dragonair, ignore Dratini encounters + chain = chain.Where(s => s.Species == (int)Species.Dragonair).ToArray(); // Yellow Dragonair, ignore Dratini encounters Gen1Version = GameVersion.YW; return true; // Dragonair (RB) case (int)Species.Dragonair: case (int)Species.Dragonite: - // Red blue dragonair have the same catch rate as dratini, it could also be a dratini from any game - vs = vs.Where(s => rate == PersonalTable.RB[s.Species].CatchRate).ToArray(); + // Red / Blue Dragonair have the same catch rate as Dratini; it could also be a Dratini from any game + chain = chain.Where(s => rate == PersonalTable.RB[s.Species].CatchRate).ToArray(); RBDragonair = true; return true; default: - vs = vs.Where(s => rate == PersonalTable.RB[s.Species].CatchRate).ToArray(); + chain = chain.Where(s => rate == PersonalTable.RB[s.Species].CatchRate).ToArray(); return true; } } @@ -128,9 +128,9 @@ private static IEnumerable GetFilteredSlots(PKM pkm, IEnumerable< } } - protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnumerable vs, int minLevel) + protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IReadOnlyList chain, int minLevel) { - var slots = Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); + var slots = Slots.Where(slot => chain.Any(evo => evo.Species == slot.Species && evo.Level >= slot.LevelMin)); if (pkm.Format >= 7 || !(pkm is PK2 pk2 && pk2.CaughtData != 0)) // transferred to Gen7+, or does not have Crystal met data return slots.Where(slot => slot.LevelMin <= minLevel); diff --git a/PKHeX.Core/Legality/Core.cs b/PKHeX.Core/Legality/Core.cs index b5aaae5da..23fdb2f7c 100644 --- a/PKHeX.Core/Legality/Core.cs +++ b/PKHeX.Core/Legality/Core.cs @@ -251,7 +251,7 @@ internal static bool IsEvolutionValid(PKM pkm, int minSpecies = -1, int 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); + var poss = EvolutionChain.GetValidPreEvolutions(pkm, maxLevel: 100, minLevel: minLevel, skipChecks: true); if (minSpecies != -1) { @@ -398,7 +398,7 @@ private static int GetMaxLevelGeneration(PKM pkm, int generation) return pkm.CurrentLevel; } - internal static int GetMinLevelEncounter(PKM pkm) + internal static int GetMaxLevelEncounter(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) diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs index 44d109113..f8b326630 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs @@ -16,7 +16,7 @@ public static IEnumerable GenerateEggs(PKM pkm, bool all = false) return GenerateEggs(pkm, evos, all); } - public static IEnumerable GenerateEggs(PKM pkm, IReadOnlyList vs, bool all = false) + public static IEnumerable GenerateEggs(PKM pkm, IReadOnlyList chain, bool all = false) { int species = pkm.Species; if (NoHatchFromEgg.Contains(species)) @@ -33,7 +33,7 @@ public static IEnumerable GenerateEggs(PKM pkm, IReadOnlyList GenerateEggs(PKM pkm, IReadOnlyList GenerateRawEncounters12(PKM pkm, Game // Calculate all 3 at the same time and pick the best result (by species). // Favor special event move gifts as Static Encounters when applicable var maxspeciesorigin = gsc ? MaxSpeciesID_2 : MaxSpeciesID_1; - var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin); + var chain = EvolutionChain.GetOriginChain(pkm, maxspeciesorigin: maxspeciesorigin); var deferred = new List(); - foreach (var t in GetValidEncounterTrades(pkm, vs, game)) + foreach (var t in GetValidEncounterTrades(pkm, chain, game)) { // some OTs are longer than the keyboard entry; don't defer these if (pkm.Format >= 7 && pkm.OT_Name.Length <= (pkm.Japanese || pkm.Korean ? 5 : 7)) @@ -155,7 +155,7 @@ private static IEnumerable GenerateRawEncounters12(PKM pkm, Game } yield return t; } - foreach (var s in GetValidStaticEncounter(pkm, vs, game)) + foreach (var s in GetValidStaticEncounter(pkm, chain, game)) { // Valid stadium and non-stadium encounters, return only non-stadium encounters, they are less restrictive switch (s.Version) @@ -179,7 +179,7 @@ private static IEnumerable GenerateRawEncounters12(PKM pkm, Game } yield return s; } - foreach (var e in GetValidWildEncounters12(pkm, vs, game)) + foreach (var e in GetValidWildEncounters12(pkm, chain, game)) { yield return e; } diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterSlotGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterSlotGenerator.cs index b2fa5487f..66f533708 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterSlotGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterSlotGenerator.cs @@ -19,17 +19,17 @@ public static class EncounterSlotGenerator public static IEnumerable GetPossible(PKM pkm, GameVersion gameSource = GameVersion.Any) { int maxspeciesorigin = GetMaxSpecies(gameSource); - var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin); - return GetPossible(pkm, vs, gameSource); + var chain = EvolutionChain.GetOriginChain(pkm, maxspeciesorigin: maxspeciesorigin); + return GetPossible(pkm, chain, gameSource); } - public static IEnumerable GetPossible(PKM pkm, IReadOnlyList vs, GameVersion gameSource = GameVersion.Any) + public static IEnumerable GetPossible(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { var possibleAreas = GetEncounterSlots(pkm, gameSource); - return possibleAreas.SelectMany(area => area.Slots).Where(z => vs.Any(v => v.Species == z.Species)); + return possibleAreas.SelectMany(area => area.Slots).Where(z => chain.Any(v => v.Species == z.Species)); } - private static IEnumerable GetRawEncounterSlots(PKM pkm, int lvl, IReadOnlyList vs, GameVersion gameSource) + private static IEnumerable GetRawEncounterSlots(PKM pkm, int lvl, IReadOnlyList chain, GameVersion gameSource) { if (pkm.Egg_Location != 0) yield break; @@ -37,7 +37,7 @@ private static IEnumerable GetRawEncounterSlots(PKM pkm, int lvl, var possibleAreas = GetEncounterAreas(pkm, gameSource); foreach (var area in possibleAreas) { - var slots = area.GetMatchingSlots(pkm, vs, lvl); + var slots = area.GetMatchingSlots(pkm, chain, lvl); foreach (var s in slots) yield return s; } @@ -54,7 +54,7 @@ private static int GetMaxSpecies(GameVersion gameSource) public static IEnumerable GetValidWildEncounters34(PKM pkm, GameVersion gameSource = GameVersion.Any) { - int lvl = GetMinLevelEncounter(pkm); + int lvl = GetMaxLevelEncounter(pkm); if (lvl <= 0) return Enumerable.Empty(); @@ -62,33 +62,33 @@ public static IEnumerable GetValidWildEncounters34(PKM pkm, GameV gameSource = (GameVersion)pkm.Version; int maxspeciesorigin = GetMaxSpecies(gameSource); - var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin); - var s = GetRawEncounterSlots(pkm, lvl, vs, gameSource); + var chain = EvolutionChain.GetOriginChain(pkm, maxspeciesorigin: maxspeciesorigin); + var slots = GetRawEncounterSlots(pkm, lvl, chain, gameSource); - return s; // defer deferrals to the method consuming this collection + return slots; // defer deferrals to the method consuming this collection } - public static IEnumerable GetValidWildEncounters12(PKM pkm, IReadOnlyList vs, GameVersion gameSource = GameVersion.Any) + public static IEnumerable GetValidWildEncounters12(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { - int lvl = GetMinLevelEncounter(pkm); + int lvl = GetMaxLevelEncounter(pkm); if (lvl <= 0) return Enumerable.Empty(); if (gameSource == GameVersion.Any) gameSource = (GameVersion)pkm.Version; - return GetRawEncounterSlots(pkm, lvl, vs, gameSource); + return GetRawEncounterSlots(pkm, lvl, chain, gameSource); } - public static IEnumerable GetValidWildEncounters(PKM pkm, IReadOnlyList vs, GameVersion gameSource = GameVersion.Any) + public static IEnumerable GetValidWildEncounters(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { if (gameSource == GameVersion.Any) gameSource = (GameVersion)pkm.Version; - int lvl = GetMinLevelEncounter(pkm); + int lvl = GetMaxLevelEncounter(pkm); if (lvl <= 0) return Enumerable.Empty(); - var s = GetRawEncounterSlots(pkm, lvl, vs, gameSource); + var s = GetRawEncounterSlots(pkm, lvl, chain, gameSource); bool IsSafariBall = pkm.Ball == (int)Ball.Safari; bool IsSportBall = pkm.Ball == (int)Ball.Sport; @@ -101,8 +101,8 @@ public static IEnumerable GetValidWildEncounters(PKM pkm, IReadOn public static IEnumerable GetValidWildEncounters(PKM pkm, GameVersion gameSource = GameVersion.Any) { int maxspeciesorigin = GetMaxSpecies(gameSource); - var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin); - return GetValidWildEncounters(pkm, vs, gameSource); + var chain = EvolutionChain.GetOriginChain(pkm, maxspeciesorigin: maxspeciesorigin); + return GetValidWildEncounters(pkm, chain, gameSource); } public static bool IsDeferred3(this EncounterSlot slot, int currentSpecies, PKM pkm, bool IsSafariBall) @@ -131,11 +131,11 @@ private static bool IsDeferred(this EncounterSlot slot, int currentSpecies, PKM private static bool IsDeferredSport(this EncounterSlot slot, bool IsSportBall) => IsSportBall != ((slot.Type & SlotType.BugContest) != 0); private static bool IsDeferredHiddenAbility(this EncounterSlot slot, bool IsHidden) => IsHidden != slot.IsHiddenAbilitySlot(); - private static IEnumerable GetValidEncounterSlots(PKM pkm, EncounterArea loc, IReadOnlyList vs, int lvl) + private static IEnumerable GetValidEncounterSlots(PKM pkm, EncounterArea loc, IReadOnlyList chain, int lvl) { if (pkm.Egg_Location != 0) return Enumerable.Empty(); - return loc.GetMatchingSlots(pkm, vs, lvl); + return loc.GetMatchingSlots(pkm, chain, lvl); } public static IEnumerable GetEncounterSlots(PKM pkm, GameVersion gameSource = GameVersion.Any) @@ -166,9 +166,9 @@ private static bool IsHiddenAbilitySlot(this EncounterSlot slot) internal static EncounterArea? GetCaptureLocation(PKM pkm) { - var vs = EvolutionChain.GetValidPreEvolutions(pkm); + var chain = EvolutionChain.GetOriginChain(pkm); return (from area in GetEncounterSlots(pkm) - let slots = GetValidEncounterSlots(pkm, area, vs, lvl: 0).ToArray() + let slots = GetValidEncounterSlots(pkm, area, chain, lvl: 0).ToArray() where slots.Length != 0 select new EncounterAreaFake { diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterStaticGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterStaticGenerator.cs index bd44a39b5..d18932263 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterStaticGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterStaticGenerator.cs @@ -25,16 +25,16 @@ public static IEnumerable GetPossible(PKM pkm, GameVersion game 2 => MaxSpeciesID_2, _ => -1 }; - var dl = EvolutionChain.GetValidPreEvolutions(pkm, maxID); + var dl = EvolutionChain.GetOriginChain(pkm, maxID); return GetPossible(pkm, dl, gameSource); } - public static IEnumerable GetPossible(PKM pkm, IReadOnlyList vs, GameVersion gameSource = GameVersion.Any) + public static IEnumerable GetPossible(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { if (gameSource == GameVersion.Any) gameSource = (GameVersion)pkm.Version; - var encs = GetStaticEncounters(pkm, vs, gameSource); + var encs = GetStaticEncounters(pkm, chain, gameSource); return encs.Where(e => ParseSettings.AllowGBCartEra || !GameVersion.GBCartEraOnly.Contains(e.Version)); } @@ -42,7 +42,7 @@ public static IEnumerable GetValidStaticEncounter(PKM pkm, Game { var poss = GetPossible(pkm, gameSource: gameSource); - int lvl = GetMinLevelEncounter(pkm); + int lvl = GetMaxLevelEncounter(pkm); if (lvl < 0) return Enumerable.Empty(); @@ -50,11 +50,11 @@ public static IEnumerable GetValidStaticEncounter(PKM pkm, Game return GetMatchingStaticEncounters(pkm, poss, lvl); } - public static IEnumerable GetValidStaticEncounter(PKM pkm, IReadOnlyList vs, GameVersion gameSource) + public static IEnumerable GetValidStaticEncounter(PKM pkm, IReadOnlyList chain, GameVersion gameSource) { - var poss = GetPossible(pkm, vs, gameSource: gameSource); + var poss = GetPossible(pkm, chain, gameSource: gameSource); - int lvl = GetMinLevelEncounter(pkm); + int lvl = GetMaxLevelEncounter(pkm); if (lvl < 0) return Enumerable.Empty(); @@ -160,7 +160,7 @@ private static EncounterStatic GetGSStaticTransfer(int species, int pkmMetLevel) case 2: return GetGSStaticTransfer(species, pkm.Met_Level); default: - var dl = EvolutionChain.GetValidPreEvolutions(pkm, lvl: 100, skipChecks: true); + var dl = EvolutionChain.GetValidPreEvolutions(pkm, maxLevel: 100, skipChecks: true); return GetPossible(pkm, dl).FirstOrDefault(); } } diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs index 1041718cd..60cf53fbf 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs @@ -9,55 +9,55 @@ public static class EncounterTradeGenerator { public static IEnumerable GetPossible(PKM pkm, GameVersion gameSource = GameVersion.Any) { - var p = EvolutionChain.GetValidPreEvolutions(pkm); + var p = EvolutionChain.GetOriginChain(pkm); return GetPossible(pkm, p, gameSource); } - public static IEnumerable GetPossible(PKM pkm, IReadOnlyList vs, GameVersion gameSource = GameVersion.Any) + public static IEnumerable GetPossible(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { if (gameSource == GameVersion.Any) gameSource = (GameVersion)pkm.Version; if (pkm.VC || pkm.Format <= 2) - return GetPossibleVC(vs, gameSource); - return GetPossibleNonVC(pkm, vs, gameSource); + return GetPossibleVC(chain, gameSource); + return GetPossibleNonVC(pkm, chain, gameSource); } public static IEnumerable GetValidEncounterTrades(PKM pkm, GameVersion gameSource = GameVersion.Any) { - var p = EvolutionChain.GetValidPreEvolutions(pkm); + var p = EvolutionChain.GetOriginChain(pkm); return GetValidEncounterTrades(pkm, p, gameSource); } - public static IEnumerable GetValidEncounterTrades(PKM pkm, IReadOnlyList p, GameVersion gameSource = GameVersion.Any) + public static IEnumerable GetValidEncounterTrades(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { if (GetIsFromGB(pkm)) - return GetValidEncounterTradesVC(pkm, p, gameSource); + return GetValidEncounterTradesVC(pkm, chain, gameSource); int lvl = IsNotTrade(pkm); if (lvl <= 0) return Enumerable.Empty(); - var poss = GetPossibleNonVC(pkm, p, gameSource); + var poss = GetPossibleNonVC(pkm, chain, gameSource); return poss.Where(z => z.IsMatch(pkm, lvl)); } - private static IEnumerable GetPossibleNonVC(PKM pkm, IReadOnlyList p, GameVersion gameSource = GameVersion.Any) + private static IEnumerable GetPossibleNonVC(PKM pkm, IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { if (gameSource == GameVersion.Any) gameSource = (GameVersion)pkm.Version; if (pkm.VC || pkm.Format <= 2) - return GetValidEncounterTradesVC(pkm, p, gameSource); + return GetValidEncounterTradesVC(pkm, chain, gameSource); var table = GetEncounterTradeTable(pkm); - return table.Where(f => p.Any(r => r.Species == f.Species)); + return table.Where(f => chain.Any(r => r.Species == f.Species)); } - private static IEnumerable GetPossibleVC(IReadOnlyList p, GameVersion gameSource = GameVersion.Any) + private static IEnumerable GetPossibleVC(IReadOnlyList chain, GameVersion gameSource = GameVersion.Any) { var table = GetEncounterTradeTableVC(gameSource); - return table.Where(f => p.Any(r => r.Species == f.Species)); + return table.Where(f => chain.Any(r => r.Species == f.Species)); } private static IEnumerable GetEncounterTradeTableVC(GameVersion gameSource) @@ -83,9 +83,9 @@ private static IEnumerable GetEncounterTradeTable(PKM pkm) }; } - private static IEnumerable GetValidEncounterTradesVC(PKM pkm, IReadOnlyList p, GameVersion gameSource) + private static IEnumerable GetValidEncounterTradesVC(PKM pkm, IReadOnlyList chain, GameVersion gameSource) { - var poss = GetPossibleVC(p, gameSource); + var poss = GetPossibleVC(chain, gameSource); if (gameSource == GameVersion.RBY) return poss.Where(z => z.IsMatchVC1(pkm)); return poss.Where(z => z.IsMatchVC2(pkm)); @@ -101,7 +101,7 @@ private static int IsNotTrade(PKM pkm) if (lang == (int)LanguageID.Hacked && !IsValidMissingLanguage(pkm)) // Japanese trades in BW have no language ID return 0; - return GetMinLevelEncounter(pkm); + return GetMaxLevelEncounter(pkm); } } } diff --git a/PKHeX.Core/Legality/Encounters/Generator/MysteryGiftGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/MysteryGiftGenerator.cs index 58f1f9e10..6a8284532 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/MysteryGiftGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/MysteryGiftGenerator.cs @@ -9,11 +9,11 @@ public static class MysteryGiftGenerator public static IEnumerable GetPossible(PKM pkm) { int maxSpecies = Legal.GetMaxSpeciesOrigin(pkm.Format); - var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxSpecies); - return GetPossible(pkm, vs); + var chain = EvolutionChain.GetOriginChain(pkm, maxSpecies); + return GetPossible(pkm, chain); } - public static IEnumerable GetPossible(PKM pkm, IReadOnlyList vs) + public static IEnumerable GetPossible(PKM pkm, IReadOnlyList chain) { // Ranger Manaphy is a PGT and is not in the PCD[] for gen4. Check manually. int gen = pkm.GenNumber; @@ -21,7 +21,7 @@ public static IEnumerable GetPossible(PKM pkm, IReadOnlyList vs.Any(dl => dl.Species == wc.Species)); + var possible = table.Where(wc => chain.Any(dl => dl.Species == wc.Species)); foreach (var enc in possible) yield return enc; } @@ -66,14 +66,14 @@ private static IEnumerable GetMatchingPCD(PKM pkm, IEnumerable private static IEnumerable GetMatchingGifts(PKM pkm, IEnumerable DB) { - var vs = EvolutionChain.GetValidPreEvolutions(pkm); - return GetMatchingGifts(pkm, DB, vs); + var chain = EvolutionChain.GetOriginChain(pkm); + return GetMatchingGifts(pkm, DB, chain); } - private static IEnumerable GetMatchingGifts(PKM pkm, IEnumerable DB, IReadOnlyList vs) + private static IEnumerable GetMatchingGifts(PKM pkm, IEnumerable DB, IReadOnlyList chain) { var deferred = new List(); - var gifts = DB.Where(wc => vs.Any(dl => dl.Species == wc.Species)); + var gifts = DB.Where(wc => chain.Any(dl => dl.Species == wc.Species)); foreach (var mg in gifts) { var result = mg.IsMatch(pkm); diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs b/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs index ab5036050..69b791fa8 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs @@ -34,7 +34,7 @@ private static List[] GetChainSingle(PKM pkm, List Com return chain; } - private static List[] GetChainAll(PKM pkm, IEncounterable Encounter, IEnumerable CompleteEvoChain) + private static List[] GetChainAll(PKM pkm, IEncounterable enc, IReadOnlyList CompleteEvoChain) { int maxgen = pkm is PK1 && !pkm.Gen1_NotTradeback ? 2 : pkm.Format; var GensEvoChains = GetChainBase(maxgen); @@ -44,7 +44,7 @@ private static List[] GetChainAll(PKM pkm, IEncounterable Encounter int lvl = pkm.CurrentLevel; int maxLevel = lvl; - int pkGen = Encounter.Generation; + int pkGen = enc.Generation; // Iterate generations backwards // Maximum level of an earlier generation (GenX) will never be greater than a later generation (GenX+Y). @@ -104,7 +104,7 @@ private static List[] GetChainAll(PKM pkm, IEncounterable Encounter } } - GensEvoChains[g] = GetEvolutionChain(pkm, Encounter, mostEvolved.Species, lvl); + GensEvoChains[g] = GetEvolutionChain(pkm, enc, mostEvolved.Species, lvl); if (GensEvoChains[g].Count == 0) continue; @@ -163,60 +163,60 @@ internal static int GetEvoChainSpeciesIndex(IReadOnlyList chain, in private static List GetEvolutionChain(PKM pkm, IEncounterable Encounter, int maxspec, int maxlevel) { - var vs = GetValidPreEvolutions(pkm, minLevel: Encounter.LevelMin); + var chain = GetValidPreEvolutions(pkm, minLevel: Encounter.LevelMin); if (Encounter.Species == maxspec) { - if (vs.Count != 1) + if (chain.Count != 1) { - vs.RemoveAll(z => z.Species != Encounter.Species); - vs[0].MinLevel = Encounter.LevelMin; + chain.RemoveAll(z => z.Species != Encounter.Species); + chain[0].MinLevel = Encounter.LevelMin; } - return vs; + return chain; } // Evolution chain is in reverse order (devolution) // Find the index of the minimum species to determine the end of the chain - int minindex = GetEvoChainSpeciesIndex(vs, Encounter.Species); - bool last = minindex < 0 || minindex == vs.Count - 1; + int minindex = GetEvoChainSpeciesIndex(chain, Encounter.Species); + bool last = minindex < 0 || minindex == chain.Count - 1; // If we remove a pre-evolution, update the chain if appropriate. if (!last) { // Remove chain species after the encounter - int count = vs.Count; + int count = chain.Count; for (int i = minindex + 1; i < count; i++) - vs.RemoveAt(i); + chain.RemoveAt(i); - if (vs.Count == 0) - return vs; // no species left in chain - CheckLastEncounterRemoval(Encounter, vs); + if (chain.Count == 0) + return chain; // no species left in chain + CheckLastEncounterRemoval(Encounter, chain); } // maxspec is used to remove future geneneration evolutions, to gather evolution chain of a pokemon in previous generations - int skip = Math.Max(0, GetEvoChainSpeciesIndex(vs, maxspec)); + int skip = Math.Max(0, GetEvoChainSpeciesIndex(chain, maxspec)); for (int i = 0; i < skip; i++) - vs.RemoveAt(0); + chain.RemoveAt(0); // Gen3->4 and Gen4->5 transfer sets the Met Level property to the Pokémon's current level. // Removes evolutions impossible before the transfer level. // For example a FireRed Charizard with a current level (in XY) is 50 but Met Level is 20; it couldn't be a Charizard in Gen3 and Gen4 games - vs.RemoveAll(e => e.MinLevel > maxlevel); + chain.RemoveAll(e => e.MinLevel > maxlevel); // Reduce the evolution chain levels to max level to limit any later analysis/results. - foreach (var d in vs) + foreach (var d in chain) d.Level = Math.Min(d.Level, maxlevel); - return vs; + return chain; } - private static void CheckLastEncounterRemoval(IEncounterable Encounter, IReadOnlyList vs) + private static void CheckLastEncounterRemoval(IEncounterable enc, IReadOnlyList chain) { - // Last entry from vs is removed, turn next entry into the encountered Pokémon - var last = vs[vs.Count - 1]; - last.MinLevel = Encounter.LevelMin; + // Last entry from chain is removed, turn next entry into the encountered Pokémon + var last = chain[chain.Count - 1]; + last.MinLevel = enc.LevelMin; last.RequiresLvlUp = false; - var first = vs[0]; + var first = chain[0]; if (first.RequiresLvlUp) return; @@ -234,17 +234,34 @@ private static void CheckLastEncounterRemoval(IEncounterable Encounter, IReadOnl } } - internal static List GetValidPreEvolutions(PKM pkm, int maxspeciesorigin = -1, int lvl = -1, int minLevel = 1, bool skipChecks = false) + internal static List GetOriginChain(PKM pkm, int maxspeciesorigin = -1, int lvl = -1, int minLevel = 1, bool skipChecks = false) { - if (lvl < 0) - lvl = pkm.CurrentLevel; + var chain = GetValidPreEvolutions(pkm, maxspeciesorigin, lvl, minLevel, skipChecks); + if (!pkm.HasOriginalMetLocation) + { + var maxLevel = Legal.GetMaxLevelEncounter(pkm); + if (maxLevel < 0) + { + chain.Clear(); + return chain; + } + foreach (var c in chain) + c.Level = Math.Min(maxLevel, c.Level); + } + return chain; + } + + internal static List GetValidPreEvolutions(PKM pkm, int maxspeciesorigin = -1, int maxLevel = -1, int minLevel = 1, bool skipChecks = false) + { + if (maxLevel < 0) + maxLevel = pkm.CurrentLevel; if (maxspeciesorigin == -1 && pkm.InhabitedGeneration(2) && pkm.Format <= 2 && pkm.GenNumber == 1) maxspeciesorigin = MaxSpeciesID_2; int tree = Math.Max(2, pkm.Format); var et = EvolutionTree.GetEvolutionTree(pkm, tree); - return et.GetValidPreEvolutions(pkm, maxLevel: lvl, maxSpeciesOrigin: maxspeciesorigin, skipChecks: skipChecks, minLevel: minLevel); + return et.GetValidPreEvolutions(pkm, maxLevel: maxLevel, maxSpeciesOrigin: maxspeciesorigin, skipChecks: skipChecks, minLevel: minLevel); } private static int GetMinLevelGeneration(PKM pkm, int generation) diff --git a/PKHeX.Core/Legality/MoveList.cs b/PKHeX.Core/Legality/MoveList.cs index 7eece355c..023d45a7d 100644 --- a/PKHeX.Core/Legality/MoveList.cs +++ b/PKHeX.Core/Legality/MoveList.cs @@ -240,7 +240,7 @@ internal static IEnumerable GetExclusivePreEvolutionMoves(PKM pkm, int Spec return preevomoves.Except(evomoves).Distinct(); } - internal static IEnumerable GetValidMoves(PKM pkm, GameVersion version, IReadOnlyList vs, int generation, int minLvLG1 = 1, int minLvLG2 = 1, bool LVL = false, bool Relearn = false, bool Tutor = false, bool Machine = false, bool MoveReminder = true, bool RemoveTransferHM = true) + internal static IEnumerable GetValidMoves(PKM pkm, GameVersion version, IReadOnlyList chain, int generation, int minLvLG1 = 1, int minLvLG2 = 1, bool LVL = false, bool Relearn = false, bool Tutor = false, bool Machine = false, bool MoveReminder = true, bool RemoveTransferHM = true) { var r = new List { 0 }; int species = pkm.Species; @@ -257,7 +257,7 @@ internal static IEnumerable GetValidMoves(PKM pkm, GameVersion version, IRe formCount = pkm.PersonalInfo.FormeCount; for (int form = 0; form < formCount; form++) - r.AddRange(GetMoves(pkm, species, minLvLG1, minLvLG2, vs[0].Level, form, Tutor, version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, generation)); + r.AddRange(GetMoves(pkm, species, minLvLG1, minLvLG2, chain[0].Level, form, Tutor, version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, generation)); if (Relearn) r.AddRange(pkm.RelearnMoves); return r.Distinct(); @@ -266,10 +266,10 @@ internal static IEnumerable GetValidMoves(PKM pkm, GameVersion version, IRe // Special Type Tutors Availability bool moveTutor = Tutor || MoveReminder; // Usually true, except when called for move suggestions (no tutored moves) - for (var i = 0; i < vs.Count; i++) + for (var i = 0; i < chain.Count; i++) { - var evo = vs[i]; - var moves = GetEvoMoves(pkm, version, vs, generation, minLvLG1, minLvLG2, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, moveTutor, i, evo); + var evo = chain[i]; + var moves = GetEvoMoves(pkm, version, chain, generation, minLvLG1, minLvLG2, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, moveTutor, i, evo); r.AddRange(moves); } @@ -285,12 +285,12 @@ internal static IEnumerable GetValidMoves(PKM pkm, GameVersion version, IRe return r.Distinct(); } - private static IEnumerable GetEvoMoves(PKM pkm, GameVersion Version, IReadOnlyList vs, int generation, int minLvLG1, int minLvLG2, bool LVL, bool Tutor, bool Machine, bool MoveReminder, bool RemoveTransferHM, bool moveTutor, int i, EvoCriteria evo) + private static IEnumerable GetEvoMoves(PKM pkm, GameVersion Version, IReadOnlyList chain, int generation, int minLvLG1, int minLvLG2, bool LVL, bool Tutor, bool Machine, bool MoveReminder, bool RemoveTransferHM, bool moveTutor, int i, EvoCriteria evo) { int minlvlevo1 = GetEvoMoveMinLevel1(pkm, generation, minLvLG1, evo); int minlvlevo2 = GetEvoMoveMinLevel2(pkm, generation, minLvLG2, evo); var maxLevel = evo.Level; - if (i != 0 && vs[i - 1].RequiresLvlUp) // evolution + if (i != 0 && chain[i - 1].RequiresLvlUp) // evolution ++maxLevel; // allow lvlmoves from the level it evolved to the next species return GetMoves(pkm, evo.Species, minlvlevo1, minlvlevo2, maxLevel, evo.Form, Tutor, Version, LVL, moveTutor, Machine, MoveReminder, RemoveTransferHM, generation); }