private static void CheckLastEncounterRemoval(IEncounterable enc, IReadOnlyList <EvoCriteria> chain) { // 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 = chain[0]; if (first.RequiresLvlUp) { return; } if (first.MinLevel == 2) { // Example: Raichu in Gen2 or later // Because Pichu requires a level up, the minimum level of the resulting Raichu must be be >2 // But after removing Pichu (because the origin species is Pikachu), the Raichu minimum level should be 1. first.MinLevel = 1; first.RequiresLvlUp = false; } else // in-game trade or evolution stone can evolve immediately { first.MinLevel = last.MinLevel; } }
/// <summary> /// Gets an object containing met data properties that might be legal. /// </summary> public static EncounterSuggestionData?GetSuggestedMetInfo(PKM pkm) { int loc = GetSuggestedTransferLocation(pkm); if (pkm.WasEgg) { return(GetSuggestedEncounterEgg(pkm, loc)); } var chain = EvolutionChain.GetValidPreEvolutions(pkm, maxLevel: 100, skipChecks: true); var w = EncounterSlotGenerator.GetCaptureLocation(pkm, chain); var s = EncounterStaticGenerator.GetStaticLocation(pkm, chain); if (w is null) { return(s is null ? null : GetSuggestedEncounter(pkm, s, loc)); } if (s is null) { return(GetSuggestedEncounter(pkm, w, loc)); } bool isDefinitelySlot = chain.Any(z => z.Species == w.Species && z.Form == w.Form); bool isDefinitelyStatic = chain.Any(z => z.Species == s.Species && z.Form == s.Form); IEncounterable obj = (isDefinitelySlot || !isDefinitelyStatic) ? w : s; return(GetSuggestedEncounter(pkm, obj, loc)); }
// Eggs private static CheckResult VerifyEncounterEgg(PKM pkm, IEncounterable egg) { pkm.WasEgg = true; // Check Species if (Legal.NoHatchFromEgg.Contains(pkm.Species)) { return(new CheckResult(Severity.Invalid, V50, CheckIdentifier.Encounter)); } switch (pkm.GenNumber) { case 1: case 2: return(new CheckResult(CheckIdentifier.Encounter)); // no met location info case 3: return(pkm.Format != 3 ? VerifyEncounterEgg3Transfer(pkm) : VerifyEncounterEgg3(pkm)); case 4: return(pkm.IsEgg ? VerifyUnhatchedEgg(pkm, 02002) : VerifyEncounterEgg4(pkm)); case 5: return(pkm.IsEgg ? VerifyUnhatchedEgg(pkm, 30003) : VerifyEncounterEgg5(pkm)); case 6: return(pkm.IsEgg ? VerifyUnhatchedEgg(pkm, 30002) : VerifyEncounterEgg6(pkm)); case 7: return(pkm.IsEgg ? VerifyUnhatchedEgg(pkm, 30002) : VerifyEncounterEgg7(pkm)); default: // none of the above return(new CheckResult(Severity.Invalid, V51, CheckIdentifier.Encounter)); } }
private static void SetFormArgument(this PKM pk, IEncounterable enc) { if (pk is IFormArgument f) { f.FormArgument = GetSuggestedFormArgument(pk, enc.Species); } }
public GBEncounterData(PKM pkm, int gen, IEncounterable enc, GameVersion game) { Game = game; Generation = gen; Encounter = enc; if (Encounter is EncounterTrade trade) { if (pkm.HasOriginalMetLocation && trade.Level < pkm.Met_Level) { Level = pkm.Met_Level; // Crystal } else { Level = trade.Level; } Type = Generation == 2 ? GBEncounterType.TradeEncounterG2 : GBEncounterType.TradeEncounterG1; } else if (Encounter is EncounterStatic statc) { Level = statc.Level; Type = statc.Moves != null && statc.Moves[0] != 0 && pkm.Moves.Contains(statc.Moves[0]) ? GBEncounterType.SpecialEncounter : GBEncounterType.StaticEncounter; } else if (Encounter is EncounterSlot1 slot) { Level = pkm.HasOriginalMetLocation && slot.LevelMin >= pkm.Met_Level && pkm.Met_Level <= slot.LevelMax ? pkm.Met_Level // Crystal : slot.LevelMin; Type = GBEncounterType.WildEncounter; } }
/// <summary> /// Sets all ribbon flags according to a legality report. /// </summary> /// <param name="pk">Pokémon to modify</param> /// <param name="allValid">Set all valid ribbons only</param> public static void SetSuggestedRibbons(this PKM pk, IEncounterable enc, bool allValid = true) { if (allValid) { RibbonApplicator.SetAllValidRibbons(pk); if (pk is PK8 pk8 && pk8.Species != (int)Species.Shedinja && pk8.GetRandomValidMark(enc, out var mark)) { pk8.SetRibbonIndex(mark); } } string report = new LegalityAnalysis(pk).Report(); if (report.Contains(string.Format(LegalityCheckStrings.LRibbonFMissing_0, ""))) { var val = string.Format(LegalityCheckStrings.LRibbonFMissing_0, ""); var ribbonList = GetRequiredRibbons(report, val); var missingRibbons = GetRibbonsRequired(pk, ribbonList); SetRibbonValues(pk, missingRibbons, 0, true); } if (report.Contains(string.Format(LegalityCheckStrings.LRibbonFInvalid_0, ""))) { var val = string.Format(LegalityCheckStrings.LRibbonFInvalid_0, ""); string[] ribbonList = GetRequiredRibbons(report, val); var invalidRibbons = GetRibbonsRequired(pk, ribbonList); SetRibbonValues(pk, invalidRibbons, 0, false); } }
private static IEnumerable <EncounterSummary> GetSummaries(IEncounterable item) { switch (item) { case EncounterSlot s: var type = s.Type; if (type == 0) { yield return(new EncounterSummary(item)); break; } for (int i = 0; i < sizeof(SlotType) * 8; i++) { var flag = (SlotType)(1 << i); if ((type & flag) != 0) { yield return(new EncounterSummary(item, flag.ToString())); } } break; default: yield return(new EncounterSummary(item)); break; } }
public static bool IsMarkAllowedSpecific(RibbonIndex mark, PKM pk, IEncounterable _) { return(mark switch { RibbonIndex.MarkCurry when !IsMarkAllowedCurry(pk) => false, RibbonIndex.MarkDestiny => false, _ => true });
private static int[] GetSpecialMoves(IEncounterable EncounterMatch) { if (EncounterMatch is IMoveset mg) { return(mg.Moves ?? new int[0]); } return(new int[0]); }
// Egg encounter public GBEncounterData(int species, GameVersion game) { Generation = 2; Game = game; Encounter = new EncounterEgg { Species = species, Game = game, Level = Level }; }
private static IReadOnlyList <int> GetSpecialMoves(IEncounterable EncounterMatch) { if (EncounterMatch is IMoveset mg) { return(mg.Moves); } return(Array.Empty <int>()); }
public void PrepareEncounter(IEncounterable npc) { lastEncounter = npc; state = State.Talking; SetLookingTarget(npc.GetTransform()); Utility.instance.ScaleGameObject(transform, new Vector3(2, 2, 2), .3f, encounterAnimationCurve); AudioManager.instance.PlaySound("EncounterTrigger"); }
// Utility private static bool IsEncounterTypeMatch(IEncounterable e, int type) { return(e switch { EncounterStaticTyped t => t.TypeEncounter.Contains(type), EncounterSlot4 w => w.TypeEncounter.Contains(type), _ => (type == 0) });
private static int[] GetSpecialMoves(IEncounterable EncounterMatch) { if (EncounterMatch is IMoveset mg) { return(mg.Moves ?? Array.Empty <int>()); } return(Array.Empty <int>()); }
private static bool IsCuteCharm4Valid(IEncounterable encounter, PKM pkm) { if (pkm.Species == 183 || pkm.Species == 184) { return(!IsCuteCharmAzurillMale(pkm.PID) || // recognized as not Azurill encounter.Species == 298); // encounter must be male Azurill } return(true); }
/// <summary> /// Gets the current <see cref="PKM.RelearnMoves"/> array of four moves that might be legal. /// </summary> /// <remarks>Use <see cref="GetSuggestedRelearnMovesFromEncounter"/> instead of calling directly; this method just puts default values in without considering the final moveset.</remarks> public static IReadOnlyList <int> GetSuggestedRelearn(this IEncounterable enc, PKM pkm) { if (ShouldNotHaveRelearnMoves(enc, pkm)) { return(Empty); } return(GetSuggestedRelearnInternal(enc, pkm)); }
private static List <EvoCriteria> GetEvolutionChain(PKM pkm, IEncounterable Encounter, int maxspec, int maxlevel) { var vs = GetValidPreEvolutions(pkm, minLevel: Encounter.LevelMin); if (Encounter.Species == maxspec) { if (vs.Count != 1) { vs.RemoveAll(z => z.Species != Encounter.Species); vs[0].MinLevel = Encounter.LevelMin; } return(vs); } // 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; // If we remove a pre-evolution, update the chain if appropriate. if (!last) { // Remove chain species after the encounter int count = vs.Count; for (int i = minindex + 1; i < count; i++) { vs.RemoveAt(i); } if (vs.Count == 0) { return(vs); // no species left in chain } CheckLastEncounterRemoval(Encounter, vs); } // 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)); for (int i = 0; i < skip; i++) { vs.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); // Reduce the evolution chain levels to max level to limit any later analysis/results. foreach (var d in vs) { d.Level = Math.Min(d.Level, maxlevel); } return(vs); }
// Egg encounter public GBEncounterData(int species, GameVersion game) { Generation = 2; Game = game; Encounter = new EncounterEgg { Species = species, Game = game, Level = 5 }; Type = GBEncounterType.EggEncounter; }
private static void AddEdgeCaseMoves(List <int> moves, IEncounterable encounter, PKM pkm) { switch (encounter) { case EncounterStatic8N r when !EncounterStatic8N.IsHighestLevelTier(pkm.Met_Level) && r.IsDownLeveled(pkm): // Downleveled Raid can happen for shared raids and self-hosted raids. moves.AddRange(MoveLevelUp.GetMovesLevelUp(pkm, r.Species, -1, -1, r.LevelMax, r.Form, GameVersion.SW, false, 8)); break; } }
private static void AddEdgeCaseMoves(List <int> moves, IEncounterable encounter, PKM pkm) { switch (encounter) { case EncounterStatic8N r when pkm.Met_Location == Encounters8Nest.SharedNest && !EncounterStatic8N.IsHighestLevelTier(pkm.Met_Level): moves.AddRange(MoveLevelUp.GetMovesLevelUp(pkm, r.Species, -1, -1, 60, r.Form, GameVersion.SW, false, 8)); break; } }
private static bool DisallowSurpriseTrade(PKM pk, IEncounterable enc) { // Anti-spam if (pk.IsNicknamed && !(enc is EncounterTrade t && t.IsNicknamed) && pk.Nickname.Length > 6) { return(true); } return(DisallowSurpriseTrade(pk)); }
private void UpdateVCTransferInfo() { EncounterOriginalGB = EncounterMatch; if (pkm.VC1) Info.EncounterMatch = EncounterGenerator.GetRBYStaticTransfer(pkm.Species, pkm.Met_Level); else if (pkm.VC2) Info.EncounterMatch = EncounterGenerator.GetGSStaticTransfer(pkm.Species, pkm.Met_Level); foreach (var z in VerifyVCEncounter(pkm, EncounterOriginalGB.Species, EncounterOriginalGB as GBEncounterData, Info.EncounterMatch as EncounterStatic)) AddLine(z); }
private static int GetForm(IEncounterable enc) { return(enc switch { EncounterSlot s => s.Form, EncounterStatic s => s.Form, MysteryGift m => m.Form, EncounterTrade t => t.Form, _ => 0 });
private static int GetEncounterFixedAbilityNumber(IEncounterable enc) { switch (enc) { case EncounterStatic s: return(s.Ability); case EncounterTrade t: return(t.Ability); default: return(-1); } }
private static GBEncounterPriority GetGBEncounterPriority(PKM pkm, IEncounterable Encounter) { return(Encounter switch { EncounterTrade1 t1 when t1.IsMatchDeferred(pkm) => GBEncounterPriority.Least, EncounterTrade1 _ => GBEncounterPriority.TradeEncounterG1, EncounterTrade2 _ => GBEncounterPriority.TradeEncounterG2, EncounterStatic _ => GBEncounterPriority.StaticEncounter, EncounterSlot _ => GBEncounterPriority.WildEncounter, _ => GBEncounterPriority.EggEncounter });
internal static EvoCriteria[][] GetEvolutionChainsAllGens(PKM pkm, IEncounterable Encounter) { var CompleteEvoChain = GetEvolutionChain(pkm, Encounter, pkm.Species, pkm.CurrentLevel); if (Encounter is EncounterInvalid || pkm.IsEgg) { return(GetChainSingle(pkm, CompleteEvoChain)); } return(GetChainAll(pkm, Encounter, CompleteEvoChain)); }
private static int[] GetSpecialMoves(IEncounterable EncounterMatch) { switch (EncounterMatch) { case IMoveset mg: return(mg.Moves ?? new int[0]); case EncounterSlot s when s.Type == SlotType.Swarm && (s.Species == 273 || s.Species == 274): return(new[] { 73 }); // Leech Seed for RSE Swarm (Seedot || Nuzleaf); only matches for RSE origin encounters. } return(new int[0]); }
public IEnumerable <CheckResult> VerifyVCEncounter(PKM pkm, IEncounterable encounter, ILocation transfer, IList <CheckMoveResult> Moves) { // Check existing EncounterMatch if (encounter is EncounterInvalid || transfer == null) { yield break; // Avoid duplicate invaild message } if (encounter is EncounterStatic v && (GameVersion.GBCartEraOnly.Contains(v.Version) || v.Version == GameVersion.VCEvents)) { bool exceptions = false; exceptions |= v.Version == GameVersion.VCEvents && encounter.Species == 151 && pkm.TID == 22796; if (!exceptions) { yield return(GetInvalid(LG1GBEncounter)); } } if (pkm.Met_Location != transfer.Location) { yield return(GetInvalid(LTransferMetLocation)); } if (pkm.Egg_Location != transfer.EggLocation) { yield return(GetInvalid(LEggLocationNone)); } // Flag Moves that cannot be transferred if (encounter is EncounterStatic s && s.Version == GameVersion.C && s.EggLocation == 256) // Dizzy Punch Gifts { FlagIncompatibleTransferMove(pkm, Moves, 146, 2); // can't have Dizzy Punch at all } bool checkShiny = pkm.VC2 || (pkm.TradebackStatus == TradebackType.WasTradeback && pkm.VC1); if (!checkShiny) { yield break; } if (pkm.Gender == 1) // female { if (pkm.PersonalInfo.Gender == 31 && pkm.IsShiny) // impossible gender-shiny { yield return(GetInvalid(LEncStaticPIDShiny, CheckIdentifier.PID)); } } else if (pkm.Species == 201) // unown { if (pkm.AltForm != 8 && pkm.AltForm != 21 && pkm.IsShiny) // impossibly form-shiny (not I or V) { yield return(GetInvalid(LEncStaticPIDShiny, CheckIdentifier.PID)); } } }
public ValidEncounterMoves(PKM pkm, LevelUpRestriction restrict, IEncounterable encounter) { var level = MoveList.GetValidMovesAllGens(pkm, restrict.EvolutionChains, minLvLG1: restrict.MinimumLevelGen1, minLvLG2: restrict.MinimumLevelGen2, Tutor: false, Machine: false, RemoveTransferHM: false); if (level[encounter.Generation] is List <int> x) { AddEdgeCaseMoves(x, encounter, pkm); } LevelUpMoves = level; TMHMMoves = MoveList.GetValidMovesAllGens(pkm, restrict.EvolutionChains, LVL: false, Tutor: false, MoveReminder: false, RemoveTransferHM: false); TutorMoves = MoveList.GetValidMovesAllGens(pkm, restrict.EvolutionChains, LVL: false, Machine: false, MoveReminder: false, RemoveTransferHM: false); }
/// <summary> /// Checks if the encounter is even valid before processing it /// </summary> /// <param name="set">showdown set</param> /// <param name="enc">encounter object</param> /// <param name="isHidden">is HA requested</param> /// <param name="destVer">version to generate in</param> /// <param name="ver">version of enc/destVer</param> /// <returns>if the encounter is valid or not</returns> private static bool IsEncounterValid(IBattleTemplate set, IEncounterable enc, bool isHidden, GameVersion destVer, out GameVersion ver) { // Pokemon who are in games of generation >= 8 can change non HA to HA via a capsule and vice versa isHidden = isHidden && destVer.GetGeneration() < 8; // initialize out vars (not calculating here to save time) ver = GameVersion.Any; // Don't process if encounter min level is higher than requested level if (enc.LevelMin > set.Level) { var isRaid = enc is EncounterStatic8N || enc is EncounterStatic8NC || enc is EncounterStatic8ND || enc is EncounterStatic8U; if (!isRaid) { return(false); } } // Don't process if Hidden Ability is requested and the PKM is from Gen 3 or Gen 4 var gen = enc.Generation; if (isHidden && (uint)(gen - 3) < 2) // Gen 3 and Gen 4 { return(false); } // Don't process if requested PKM is Gigantamax but the Game is not SW/SH ver = enc is IVersion v ? v.Version : destVer; if (set.CanGigantamax && !GameVersion.SWSH.Contains(ver)) { return(false); } // Don't process if Game is LGPE and requested PKM is not Kanto / Meltan / Melmetal // Don't process if Game is SWSH and requested PKM is not from the Galar Dex (Zukan8.DexLookup) if (GameVersion.GG.Contains(destVer)) { return(set.Species <= 151 || set.Species == 808 || set.Species == 809); } if (GameVersion.SWSH.Contains(destVer)) { return(((PersonalInfoSWSH)PersonalTable.SWSH.GetFormeEntry(set.Species, set.FormIndex)).IsPresentInGame || SimpleEdits.Zukan8Additions.Contains(set.Species)); } if (set.Species > destVer.GetMaxSpeciesID()) { return(false); } // Encounter should hopefully be possible return(true); }