public static IEnumerable <IEncounterable> GenerateEggs(PKM pkm, IReadOnlyList <EvoCriteria> chain) { var canBeEgg = GetCanBeEgg(pkm); if (!canBeEgg) { yield break; } var baseID = chain[chain.Count - 1]; if ((baseID.Species >= MaxSpeciesID_2 || baseID.Form != 0) && chain.Count != 1) { baseID = chain[chain.Count - 2]; } if (baseID.Form != 0) { yield break; // Forms don't exist in Gen2, besides Unown (which can't breed). Nothing can form-change. } int species = baseID.Species; if (ParseSettings.AllowGen2Crystal(pkm)) { yield return(new EncounterEgg(species, 0, 5, 2, GameVersion.C)); // gen2 egg } yield return(new EncounterEgg(species, 0, 5, 2, GameVersion.GS)); // gen2 egg }
public LevelUpRestriction(PKM pkm, LegalInfo info) { MinimumLevelGen1 = pkm.GenNumber <= 2 ? info.EncounterMatch.LevelMin + 1 : 0; MinimumLevelGen2 = ParseSettings.AllowGen2MoveReminder(pkm) ? 1 : info.EncounterMatch.LevelMin + 1; EncounterSpecies = info.EncounterMatch.Species; EvolutionChains = info.EvoChainsAllGens; }
private static IEnumerable <EncounterArea> GetEncounterTableGSC(PKM pkm) { if (!ParseSettings.AllowGen2Crystal(pkm)) { return(SlotsGS); } // Gen 2 met location is lost outside gen 2 games if (pkm.Format != 2) { return(SlotsGSC); } // Format 2 with met location, encounter should be from Crystal if (pkm.HasOriginalMetLocation) { return(SlotsC); } // Format 2 without met location but pokemon could not be tradeback to gen 1, // encounter should be from gold or silver if (pkm.Species > 151 && !FutureEvolutionsGen1.Contains(pkm.Species)) { return(SlotsGS); } // Encounter could be any gen 2 game, it can have empty met location for have a g/s origin // or it can be a Crystal pokemon that lost met location after being tradeback to gen 1 games return(SlotsGSC); }
private static CheckMoveResult[] ParseMovesForEncounters(PKM pkm, LegalInfo info, IReadOnlyList <int> currentMoves) { if (pkm.Species == (int)Species.Smeargle) // special handling for Smeargle { return(ParseMovesForSmeargle(pkm, currentMoves, info)); // Smeargle can have any moves except a few } // gather valid moves for encounter species var restrict = new LevelUpRestriction(pkm, info); info.EncounterMoves = new ValidEncounterMoves(pkm, restrict, info.EncounterMatch); IReadOnlyList <int> defaultG1LevelMoves = Array.Empty <int>(); IReadOnlyList <int> defaultG2LevelMoves = Array.Empty <int>(); var defaultTradeback = pkm.TradebackStatus; bool gb = false; int gen = info.EncounterMatch.Generation; if (gen <= 2) { gb = true; defaultG1LevelMoves = info.EncounterMoves.LevelUpMoves[1]; if (pkm.InhabitedGeneration(2)) { defaultG2LevelMoves = info.EncounterMoves.LevelUpMoves[2]; } // Generation 1 can have different minimum level in different encounter of the same species; update valid level moves UpdateGen1LevelUpMoves(pkm, info.EncounterMoves, restrict.MinimumLevelGen1, gen, info); // The same for Generation 2; if move reminder from Stadium 2 is not allowed if (!ParseSettings.AllowGen2MoveReminder(pkm) && pkm.InhabitedGeneration(2)) { UpdateGen2LevelUpMoves(pkm, info.EncounterMoves, restrict.MinimumLevelGen2, gen, info); } } var res = info.Generation < 6 ? ParseMovesPre3DS(pkm, currentMoves, info) : ParseMoves3DS(pkm, currentMoves, info); if (res.All(x => x.Valid)) { return(res); } // not valid if (gb) // restore generation 1 and 2 moves { info.EncounterMoves.LevelUpMoves[1] = defaultG1LevelMoves; if (pkm.InhabitedGeneration(2)) { info.EncounterMoves.LevelUpMoves[2] = defaultG2LevelMoves; } } pkm.TradebackStatus = defaultTradeback; return(res); }
private static int GetEvoMoveMinLevel2(PKM pkm, int Generation, int minLvLG2, EvoCriteria evo) { if (Generation != 2 || ParseSettings.AllowGen2MoveReminder(pkm)) { return(1); } if (evo.MinLevel > 1) { return(Math.Min(pkm.CurrentLevel, evo.MinLevel)); } return(minLvLG2); }
private static int GetEvoMoveMinLevel2(PKM pkm, int generation, int minLvLG2, EvoCriteria evo) { if (generation != 2 || ParseSettings.AllowGen2MoveReminder(pkm)) { return(1); } // For evolutions, return the lower of the two; current level should legally be >= if (evo.MinLevel > 1) { return(Math.Min(pkm.CurrentLevel, evo.MinLevel)); } return(minLvLG2); }
private static IEnumerable <EncounterStatic> GetEncounterStaticTableGSC(PKM pkm) { if (!ParseSettings.AllowGen2Crystal(pkm)) { return(StaticGS); } if (pkm.Format != 2) { return(StaticGSC); } if (pkm.HasOriginalMetLocation) { return(StaticC); } return(StaticGSC); }
private static GameVersion GetIsTutor2(PKM pkm, int species, int move) { if (!ParseSettings.AllowGen2Crystal(pkm)) { return(NONE); } var info = PersonalTable.C[species]; for (int i = 0; i < Tutors_GSC.Length; i++) { if (Tutors_GSC[i] == move) { return(info.TMHM[57 + i] ? GameVersion.C : NONE); } } return(GetIsTutor1(pkm, species, move)); }
private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { if (info.EncounterMatch is EncounterEgg e) { return(pkm.IsEgg ? ParseMovesIsEggPreRelearn(pkm, currentMoves, e) : ParseMovesWasEggPreRelearn(pkm, currentMoves, info, e)); } int gen = info.EncounterMatch.Generation; if (gen <= 2 && (gen == 1 || (gen == 2 && !ParseSettings.AllowGen2MoveReminder(pkm)))) // fixed encounter moves without relearning { return(ParseMovesGenGB(pkm, currentMoves, info)); } return(ParseMovesSpecialMoveset(pkm, currentMoves, info)); }
private static void VerifyMiscEggCommon(LegalityAnalysis data) { var pkm = data.pkm; if (pkm.Move1_PPUps > 0 || pkm.Move2_PPUps > 0 || pkm.Move3_PPUps > 0 || pkm.Move4_PPUps > 0) { data.AddLine(GetInvalid(LEggPPUp, Egg)); } if (pkm.Move1_PP != pkm.GetMovePP(pkm.Move1, 0) || pkm.Move2_PP != pkm.GetMovePP(pkm.Move2, 0) || pkm.Move3_PP != pkm.GetMovePP(pkm.Move3, 0) || pkm.Move4_PP != pkm.GetMovePP(pkm.Move4, 0)) { data.AddLine(GetInvalid(LEggPP, Egg)); } var EncounterMatch = data.EncounterOriginal; var HatchCycles = EncounterMatch is EncounterStatic s ? s.EggCycles : 0; if (HatchCycles == 0) // no value set { HatchCycles = pkm.PersonalInfo.HatchCycles; } if (pkm.OT_Friendship > HatchCycles) { data.AddLine(GetInvalid(LEggHatchCycles, Egg)); } if (pkm.Format >= 6 && EncounterMatch is EncounterEgg && !pkm.Moves.SequenceEqual(pkm.RelearnMoves)) { var moves = string.Join(", ", ParseSettings.GetMoveNames(pkm.Moves)); var msg = string.Format(LMoveFExpect_0, moves); data.AddLine(GetInvalid(msg, Egg)); } if (pkm is PK8 pk8) { if (pk8.HasAnyMoveRecordFlag()) { data.AddLine(GetInvalid(LEggRelearnFlags, Egg)); } if (pk8.StatNature != pk8.Nature) { data.AddLine(GetInvalid(LEggNature, Egg)); } } }
/// <summary> /// Initializes PKHeX's runtime strings to the specified language. /// </summary> /// <param name="lang">2-char language ID</param> /// <param name="sav">Save data (optional)</param> /// <param name="hax">Permit illegal things (items, only)</param> public static void InitializeStrings(string lang, SaveFile?sav = null, bool hax = false) { var str = GameInfo.Strings = GameInfo.GetStrings(lang); if (sav != null) { GameInfo.FilteredSources = new FilteredGameDataSource(sav, GameInfo.Sources, hax); } // Update Legality Analysis strings ParseSettings.ChangeLocalizationStrings(str.movelist, str.specieslist); // Update Legality Strings Task.Run(() => { RibbonStrings.ResetDictionary(str.ribbons); LocalizationUtil.SetLocalization(typeof(LegalityCheckStrings), lang); LocalizationUtil.SetLocalization(typeof(MessageStrings), lang); }); }
private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, int[] Moves, LegalInfo info) { if (pkm.IsEgg && info.EncounterMatch is EncounterEgg egg) { var SpecialMoves = GetSpecialMoves(info.EncounterMatch); return(ParseMovesIsEggPreRelearn(pkm, Moves, SpecialMoves, egg)); } if (info.EncounterMatch is EncounterEgg e) { return(ParseMovesWasEggPreRelearn(pkm, Moves, info, e)); } int gen = info.EncounterMatch.Generation; if (gen <= 2 && (gen == 1 || (gen == 2 && !ParseSettings.AllowGen2MoveReminder(pkm)))) // fixed encounter moves without relearning { return(ParseMovesGenGB(pkm, Moves, info)); } return(ParseMovesSpecialMoveset(pkm, Moves, info)); }
public static IEnumerable <EncounterEgg> GenerateEggs(PKM pkm, IReadOnlyList <EvoCriteria> chain, bool all = false) { int species = pkm.Species; if (!Breeding.CanHatchAsEgg(species)) { yield break; } var canBeEgg = all || GetCanBeEgg(pkm); if (!canBeEgg) { yield break; } // Gen2 was before split-breed species existed; try to ensure that the egg we try and match to can actually originate in the game. // Species must be < 251 // Form must be 0 (Unown cannot breed). var baseID = chain[chain.Count - 1]; if ((baseID.Species >= Legal.MaxSpeciesID_2 || baseID.Form != 0) && chain.Count != 1) { baseID = chain[chain.Count - 2]; } if (baseID.Form != 0) { yield break; // Forms don't exist in Gen2, besides Unown (which can't breed). Nothing can form-change. } species = baseID.Species; if (species > Legal.MaxSpeciesID_2) { yield break; } if (ParseSettings.AllowGen2Crystal(pkm)) { yield return(new EncounterEgg(species, 0, 5, 2, GameVersion.C)); // gen2 egg } yield return(new EncounterEgg(species, 0, 5, 2, GameVersion.GS)); // gen2 egg }
public static IEnumerable <IEncounterable> GenerateEggs(PKM pkm, List <EvoCriteria> chain) { var canBeEgg = GetCanBeEgg(pkm); if (!canBeEgg) { yield break; } var baseID = chain[chain.Count - 1]; if ((baseID.Species >= MaxSpeciesID_2 || baseID.Form != 0) && chain.Count != 1) { baseID = chain[chain.Count - 2]; } int species = baseID.Species; if (ParseSettings.AllowGen2Crystal(pkm)) { yield return(new EncounterEgg(species, 0, 5, 2, GameVersion.C)); // gen2 egg } yield return(new EncounterEgg(species, 0, 5, 2, GameVersion.GS)); // gen2 egg }
/// <summary> /// Checks if a Gen1 trade evolution must have occurred. /// </summary> private static bool IsTradeEvolutionRequired(LegalityAnalysis data, IEncounterTemplate enc) { // There is no way to prevent a Gen1 trade evolution, as held items (Everstone) did not exist. // Machoke, Graveler, Haunter and Kadabra captured in the second phase evolution, excluding in-game trades, are already checked var pkm = data.pkm; var species = pkm.Species; // This check is only applicable if it's a trade evolution that has not been evolved. if (!GBRestrictions.Trade_Evolution1.Contains(enc.Species) || enc.Species != species) { return(false); } // Context check is only applicable to gen1/2; transferring to Gen2 is a trade. // Stadium 2 can transfer across game/generation boundaries without initiating a trade. // Ignore this check if the environment's loaded trainer is not from Gen1/2 or is from GB Era. if (ParseSettings.ActiveTrainer.Generation >= 3 || ParseSettings.AllowGBCartEra) { return(false); } // Gen2 stuff can be traded between Gen2 games holding an Everstone, assuming it hasn't been transferred to Gen1 for special moves. if (enc.Generation == 2) { return(data.Info.Moves.All(z => z.Generation == 2)); } // Gen1 stuff can only be un-evolved if it was never traded from the OT. if (data.Info.Moves.Any(z => z.Generation != 1)) { return(true); // traded to Gen2 for special moves } if (pkm.Format != 1) { return(true); // traded to Gen2 (current state) } return(!ParseSettings.IsFromActiveTrainer(pkm)); // not with OT }
private void VerifyG1TradeEvo(LegalityAnalysis data) { if (ParseSettings.ActiveTrainer.Generation >= 3) return; // context check is only applicable to gen1/2; transferring to gen2 is a trade. var pkm = data.pkm; var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && !ParseSettings.IsFromActiveTrainer(pkm)) || GBRestrictions.IsTradedKadabraG1(pkm); if (!mustevolve) return; // Pokemon have been traded but it is not evolved, trade evos are sequential dex numbers var evolved = LegalityAnalysis.SpeciesStrings[pkm.Species + 1]; var unevolved = LegalityAnalysis.SpeciesStrings[pkm.Species]; data.AddLine(GetInvalid(string.Format(LEvoTradeReqOutsider, unevolved, evolved))); }
private static IEnumerable <IEncounterable> GenerateRawEncounters12(PKM pkm, GameVersion game) { bool gsc = GameVersion.GSC.Contains(game); // Since encounter matching is super weak due to limited stored data in the structure // 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 deferred = new List <IEncounterable>(); foreach (var t in GetValidEncounterTrades(pkm, vs, 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)) { deferred.Add(t); continue; } yield return(t); } foreach (var s in GetValidStaticEncounter(pkm, vs, game)) { // Valid stadium and non-stadium encounters, return only non-stadium encounters, they are less restrictive switch (s.Version) { case GameVersion.Stadium: case GameVersion.Stadium2: deferred.Add(s); continue; case GameVersion.EventsGBGen2: if (!s.EggEncounter && !pkm.HasOriginalMetLocation) { continue; } if (pkm.Japanese) { deferred.Add(s); } continue; case GameVersion.C when gsc && pkm.Format == 2: // Crystal specific data needs to be present if (!s.EggEncounter && !pkm.HasOriginalMetLocation) { continue; } if (s.Species == 251 && ParseSettings.AllowGBCartEra) // no celebi, the GameVersion.EventsGBGen2 will pass thru { continue; } break; } yield return(s); } foreach (var e in GetValidWildEncounters12(pkm, vs, game)) { yield return(e); } if (gsc) { var canBeEgg = GetCanBeEgg(pkm); if (canBeEgg) { int eggspec = GetBaseEggSpecies(pkm); if (ParseSettings.AllowGen2Crystal(pkm)) { yield return new EncounterEgg { Species = eggspec, Version = GameVersion.C, Level = 5 } } ; // gen2 egg yield return(new EncounterEgg { Species = eggspec, Version = GameVersion.GS, Level = 5 }); // gen2 egg } } foreach (var d in deferred) { yield return(d); } }
private void VerifyG1TradeEvo(LegalityAnalysis data) { var pkm = data.pkm; var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && !ParseSettings.IsFromActiveTrainer(pkm)) || GBRestrictions.IsTradedKadabraG1(pkm); if (!mustevolve) { return; } // Pokemon have been traded but it is not evolved, trade evos are sequential dex numbers var unevolved = LegalityAnalysis.SpeciesStrings[pkm.Species]; var evolved = LegalityAnalysis.SpeciesStrings[pkm.Species + 1]; data.AddLine(GetInvalid(string.Format(LEvoTradeReqOutsider, unevolved, evolved))); }
private void VerifyG1TradeEvo(LegalityAnalysis data) { // Context check is only applicable to gen1/2; transferring to Gen2 is a trade. // Stadium 2 can transfer across game/generation boundaries without initiating a trade. if (ParseSettings.ActiveTrainer.Generation >= 3 || ParseSettings.AllowGBCartEra) { return; } var pkm = data.pkm; var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && !ParseSettings.IsFromActiveTrainer(pkm)) || GBRestrictions.IsTradedKadabraG1(pkm); if (!mustevolve) { return; } // Pokemon have been traded but it is not evolved, trade evolutions are sequential dex numbers var evolved = ParseSettings.SpeciesStrings[pkm.Species + 1]; var unevolved = ParseSettings.SpeciesStrings[pkm.Species]; data.AddLine(GetInvalid(string.Format(LEvoTradeReqOutsider, unevolved, evolved))); }
private static IEnumerable <IEncounterable> GenerateRawEncounters12(PKM pkm, GameVersion game) { bool gsc = GameVersion.GSC.Contains(game); // Since encounter matching is super weak due to limited stored data in the structure // 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 deferred = new List <IEncounterable>(); foreach (var t in GetValidEncounterTrades(pkm, vs, game)) { if (pkm.Format >= 7 && (t.Generation == 2 || t.GetOT(pkm.Language) != pkm.OT_Name)) // ot length collision { deferred.Add(t); continue; } yield return(t); } foreach (var s in GetValidStaticEncounter(pkm, vs, game)) { // Valid stadium and non-stadium encounters, return only non-stadium encounters, they are less restrictive switch (s.Version) { case GameVersion.Stadium: case GameVersion.Stadium2: deferred.Add(s); continue; case GameVersion.EventsGBGen2: if (!s.EggEncounter && !pkm.HasOriginalMetLocation) { continue; } if (pkm.Japanese) { deferred.Add(s); } continue; case GameVersion.C when gsc && pkm.Format == 2: // Crystal specific data needs to be present if (!s.EggEncounter && !pkm.HasOriginalMetLocation) { continue; } if (s.Species == 251 && ParseSettings.AllowGBCartEra) // no celebi, the GameVersion.EventsGBGen2 will pass thru { continue; } break; } yield return(s); } // clear egg flag // necessary for static egg gifts which appear in wild, level 8 GS clefairy // GetValidWildEncounters immediately returns empty otherwise pkm.WasEgg = false; foreach (var e in GetValidWildEncounters12(pkm, vs, game)) { yield return(e); } if (gsc) { bool WasEgg = !pkm.Gen1_NotTradeback && GetWasEgg23(pkm) && !NoHatchFromEgg.Contains(pkm.Species); if (WasEgg) { // Further Filtering if (pkm.Format < 3) { WasEgg &= pkm.Met_Location == 0 || pkm.Met_Level == 1; // 2->1->2 clears met info WasEgg &= pkm.CurrentLevel >= 5; } } if (WasEgg) { int eggspec = GetBaseEggSpecies(pkm); if (ParseSettings.AllowGen2Crystal(pkm)) { yield return new EncounterEgg { Species = eggspec, Version = GameVersion.C, Level = 5 } } ; // gen2 egg yield return(new EncounterEgg { Species = eggspec, Version = GameVersion.GS, Level = 5 }); // gen2 egg } } foreach (var d in deferred) { yield return(d); } }