private void VerifyHTMemoryTransferTo7(LegalityAnalysis data, PKM pkm, LegalInfo Info) { // Bank Transfer adds in the Link Trade Memory. // Trading 7<->7 between games (not Bank) clears this data. if (pkm.HT_Memory == 0) { VerifyHTMemoryNone(data, pkm); return; } // Transfer 6->7 & withdraw to same HT => keeps past gen memory // Don't require link trade memory for these past gen cases int gen = Info.Generation; if (3 <= gen && gen < 7 && pkm.CurrentHandler == 1) { return; } if (pkm.HT_Memory != 4) { data.AddLine(Severity.Invalid, LMemoryIndexLinkHT, CheckIdentifier.Memory); } if (pkm.HT_TextVar != 0) { data.AddLine(Severity.Invalid, LMemoryIndexArgHT, CheckIdentifier.Memory); } if (pkm.HT_Intensity != 1) { data.AddLine(Severity.Invalid, LMemoryIndexIntensityHT1, CheckIdentifier.Memory); } if (pkm.HT_Feeling > 10) { data.AddLine(Severity.Invalid, LMemoryIndexFeelHT09, CheckIdentifier.Memory); } }
private CheckResult VerifyBallEquals(LegalityAnalysis data, int ball) => GetResult(ball == data.pkm.Ball);
private CheckResult VerifyBallEggGen6(LegalityAnalysis data) { var pkm = data.pkm; int species = data.EncounterMatch.Species; if (pkm.Gender == 2 || Legal.BreedMaleOnly.Contains(species)) // Genderless { return(VerifyBallEquals(data, (int)Poke)); // Must be Pokéball as ball can only pass via mother (not Ditto!) } Ball ball = (Ball)pkm.Ball; if (ball == Safari) // Safari Ball { if (!Legal.Inherit_Safari.Contains(species)) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4) { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (ball.IsApricornBall()) // Apricorn Ball { if (!Legal.Inherit_Apricorn6.Contains(species)) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4) { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (ball == Sport) // Sport Ball { if (!Legal.Inherit_Sport.Contains(species)) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4) { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (ball == Dream) // Dream Ball { if (pkm.AbilityNumber == 4 && Legal.Ban_DreamHidden.Contains(species)) { return(GetInvalid(LBallAbility)); } if (Legal.Inherit_Dream.Contains(species)) { return(GetValid(LBallSpeciesPass)); } return(GetInvalid(LBallSpecies)); } if (Dusk <= ball && ball <= Quick) // Dusk Heal Quick { if (!Legal.Ban_Gen4Ball_6.Contains(species)) { return(GetValid(LBallSpeciesPass)); } return(GetInvalid(LBallSpecies)); } if (Ultra <= ball && ball <= Premier) // Don't worry, Safari was already checked. { if (Legal.Ban_Gen3Ball.Contains(species)) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4 && Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm)) { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (species > 650 && species != 700) // Sylveon { if (Legal.WildPokeballs6.Contains(pkm.Ball)) { return(GetValid(LBallSpeciesPass)); } return(GetInvalid(LBallSpecies)); } if (ball >= Dream) { return(GetInvalid(LBallUnavailable)); } return(NONE); }
public override void Verify(LegalityAnalysis data) { var result = VerifyAbility(data); data.AddLine(result); }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; switch (data.EncounterMatch) { case EncounterTrade _: case MysteryGift g when !g.IsEgg: case EncounterStatic5N _: return; // already verified } var ot = pkm.OT_Name; if (ot.Length == 0) { data.AddLine(GetInvalid(LOTShort)); } if (pkm.TID == 0 && pkm.SID == 0) { data.AddLine(Get(LOT_IDs0, Severity.Fishy)); } else if (pkm.VC) { if (pkm.SID != 0) { data.AddLine(GetInvalid(LOT_SID0Invalid)); } } else if (pkm.TID == pkm.SID) { data.AddLine(Get(LOT_IDEqual, Severity.Fishy)); } else if (pkm.TID == 0) { data.AddLine(Get(LOT_TID0, Severity.Fishy)); } else if (pkm.SID == 0) { data.AddLine(Get(LOT_SID0, Severity.Fishy)); } else if ((pkm.TID == 12345 && pkm.SID == 54321) || IsOTNameSuspicious(ot)) { data.AddLine(Get(LOTSuspicious, Severity.Fishy)); } if (pkm.VC) { VerifyOTG1(data); } else if (ot.Length > Legal.GetMaxLengthOT(data.Info.Generation, (LanguageID)pkm.Language)) { if (!IsEdgeCaseLength(pkm, data.EncounterOriginal, ot)) { data.AddLine(Get(LOTLong, Severity.Invalid)); } } if (ParseSettings.CheckWordFilter) { if (WordFilter.IsFiltered(ot, out string bad)) { data.AddLine(GetInvalid($"Wordfilter: {bad}")); } if (WordFilter.IsFiltered(pkm.HT_Name, out bad)) { data.AddLine(GetInvalid($"Wordfilter: {bad}")); } if (ContainsTooManyNumbers(ot, data.Info.Generation)) { data.AddLine(GetInvalid($"Wordfilter: Too many numbers.")); } } }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; var EncounterMatch = data.EncounterOriginal; // If the Pokémon is not nicknamed, it should match one of the language strings. if (pkm.Nickname.Length == 0) { data.AddLine(GetInvalid(LNickLengthShort)); return; } if (pkm.Species > SpeciesName.SpeciesLang[0].Count) { data.AddLine(Get(LNickLengthShort, Severity.Indeterminate)); return; } if (pkm.VC && pkm.IsNicknamed) { VerifyG1NicknameWithinBounds(data, pkm.Nickname); } else if (EncounterMatch is MysteryGift m) { if (pkm.IsNicknamed && !m.IsEgg) { data.AddLine(Get(LEncGiftNicknamed, ParseSettings.NicknamedMysteryGift)); } } if (EncounterMatch is EncounterTrade t) { VerifyNicknameTrade(data, t); return; } if (pkm.IsEgg) { VerifyNicknameEgg(data); return; } string nickname = pkm.Nickname.Replace('\'', '’'); if (VerifyUnNicknamedEncounter(data, pkm, nickname)) { return; } // Non-nicknamed strings have already been checked. if (ParseSettings.CheckWordFilter && pkm.IsNicknamed) { if (WordFilter.IsFiltered(nickname, out string bad)) { data.AddLine(GetInvalid($"Wordfilter: {bad}")); } if (TrainerNameVerifier.ContainsTooManyNumbers(nickname, data.Info.Generation)) { data.AddLine(GetInvalid("Wordfilter: Too many numbers.")); } } }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; if (pkm.IsEgg) { VerifyMiscEggCommon(data); if (pkm is IContestStats s && s.HasContestStats()) { data.AddLine(GetInvalid(LEggContest, Egg)); } switch (pkm) { case PK5 pk5 when pk5.PokeStarFame != 0 && pk5.IsEgg: data.AddLine(GetInvalid(LEggShinyPokeStar, Egg)); break; case PK4 pk4 when pk4.ShinyLeaf != 0: data.AddLine(GetInvalid(LEggShinyLeaf, Egg)); break; case PK4 pk4 when pk4.PokéathlonStat != 0: data.AddLine(GetInvalid(LEggPokeathlon, Egg)); break; case PK3 _ when pkm.Language != 1: // All Eggs are Japanese and flagged specially for localized string data.AddLine(GetInvalid(string.Format(LOTLanguage, LanguageID.Japanese, (LanguageID)pkm.Language), Egg)); break; } if (pkm is IHomeTrack home && home.Tracker != 0) { data.AddLine(GetInvalid(LTransferTrackerShouldBeZero)); } } else { VerifyMiscMovePP(data); } switch (pkm) { case PK7 pk7 when pk7.ResortEventStatus >= 20: data.AddLine(GetInvalid(LTransferBad)); break; case PB7 pb7: VerifyBelugaStats(data, pb7); break; case PK8 pk8: VerifySWSHStats(data, pk8); break; } if (pkm.Format >= 6) { VerifyFullness(data, pkm); } VerifyMiscFatefulEncounter(data); }
private void VerifyMedalsRegular(LegalityAnalysis data) { var pkm = data.pkm; var Info = data.Info; uint value = BitConverter.ToUInt32(pkm.Data, 0x2C); if ((value & 3) != 0) // 2 unused flags { data.AddLine(GetInvalid(LSuperUnused)); } int TrainCount = pkm.SuperTrainingMedalCount(); if (pkm.IsEgg) { // Can't have any super training data as an egg. if (TrainCount > 0) { data.AddLine(GetInvalid(LSuperEgg)); } if (pkm.SecretSuperTrainingUnlocked) { data.AddLine(GetInvalid(LSuperNoUnlocked)); } if (pkm.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperNoComplete)); } return; } if (Info.Generation >= 7 || Info.Generation <= 2) { // Can't have any super training data if it never visited Gen6. if (TrainCount > 0) { data.AddLine(GetInvalid(LSuperUnavailable)); } if (pkm.SecretSuperTrainingUnlocked) { data.AddLine(GetInvalid(LSuperNoUnlocked)); } if (pkm.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperNoComplete)); } return; } if (pkm.Format >= 7) { // Gen6->Gen7 transfer wipes the two Secret flags. if (pkm.SecretSuperTrainingUnlocked) { data.AddLine(GetInvalid(LSuperNoUnlocked)); } if (pkm.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperNoComplete)); } return; } // Only reach here if Format==6. if (TrainCount == 30 ^ pkm.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperComplete)); } }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; var EncounterMatch = data.EncounterOriginal; if (EncounterMatch is MysteryGift gift) { if (gift.Level != pkm.Met_Level && pkm.HasOriginalMetLocation) { switch (gift) { case WC3 wc3 when wc3.Met_Level == pkm.Met_Level || wc3.IsEgg: break; case WC7 wc7 when wc7.MetLevel == pkm.Met_Level: break; default: data.AddLine(GetInvalid(LLevelMetGift)); return; } } if (gift.Level > pkm.CurrentLevel) { data.AddLine(GetInvalid(LLevelMetGiftFail)); return; } } if (pkm.IsEgg) { int elvl = Legal.GetEggHatchLevel(pkm); if (elvl != pkm.CurrentLevel) { data.AddLine(GetInvalid(string.Format(LEggFMetLevel_0, elvl))); return; } var reqEXP = EncounterMatch is EncounterStatic s && s.Version == GameVersion.C ? 125 // Gen2 Dizzy Punch gifts always have 125 EXP, even if it's more than the Lv5 exp required. : Experience.GetEXP(elvl, pkm.Species, pkm.AltForm); if (reqEXP != pkm.EXP) { data.AddLine(GetInvalid(LEggEXP)); } return; } int lvl = pkm.CurrentLevel; if (lvl < pkm.Met_Level) { data.AddLine(GetInvalid(LLevelMetBelow)); } else if (!EncounterMatch.IsWithinRange(pkm) && lvl != 100 && pkm.EXP == Experience.GetEXP(lvl, pkm.Species, pkm.AltForm)) { data.AddLine(Get(LLevelEXPThreshold, Severity.Fishy)); } else { data.AddLine(GetValid(LLevelMetSane)); } }
private CheckResult VerifyBallEggGen7(LegalityAnalysis data) { var pkm = data.pkm; int species = data.EncounterMatch.Species; if (722 <= species && species <= 730) // G7 Starters { return(VerifyBallEquals(data, 4)); } int ball = pkm.Ball; if (ball == 0x05) // Safari Ball { if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species))) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4 && Legal.Ban_SafariBallHidden_7.Contains(species)) { return(GetInvalid(V122)); } return(GetValid(V123)); } if (0x10 < ball && ball < 0x18) // Apricorn Ball { if (!Legal.Inherit_Apricorn7.Contains(species)) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden7Apricorn.Contains(species | pkm.AltForm << 11)) // lineage is 3->2->origin { return(GetInvalid(V122)); } return(GetValid(V123)); } if (ball == 0x18) // Sport Ball { if (!Legal.Inherit_Sport.Contains(species)) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4 && (species == 313 || species == 314)) // Volbeat/Illumise { return(GetInvalid(V122)); } return(GetValid(V123)); } if (ball == 0x19) // Dream Ball { if (Legal.Inherit_Dream.Contains(species) || Legal.Inherit_DreamMale.Contains(species)) { return(GetValid(V123)); } return(GetInvalid(V121)); } if (0x0D <= ball && ball <= 0x0F) // Dusk Heal Quick { if (!Legal.Ban_Gen4Ball_7.Contains(species)) { return(GetValid(V123)); } return(GetInvalid(V121)); } if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked. { if (!Legal.Ban_Gen3Ball_7.Contains(species)) { return(GetValid(V123)); } return(GetInvalid(V121)); } if (ball == 26) { if (species == 669 && pkm.AltForm == 3 && pkm.AbilityNumber == 4) { return(GetInvalid(V122)); // Can't obtain Flabébé-Blue with Hidden Ability in wild } if ((species > 731 && species <= 785) || (Legal.PastGenAlolanNatives.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species))) { return(GetValid(V123)); } if (Legal.PastGenAlolanScans.Contains(species)) { return(GetValid(V123)); } // next statement catches all new alolans } if (species > 721) { return(VerifyBallEquals(data, Legal.WildPokeballs7)); } if (ball >= 27) { return(GetInvalid(V126)); } return(NONE); }
private CheckResult VerifyBallEggGen6(LegalityAnalysis data) { var pkm = data.pkm; int species = data.EncounterMatch.Species; if (pkm.Gender == 2 || Legal.BreedMaleOnly.Contains(species)) // Genderless { return(VerifyBallEquals(data, 4)); // Must be Pokéball as ball can only pass via mother (not Ditto!) } int ball = pkm.Ball; if (ball >= 26) { return(GetInvalid(V126)); } if (ball == 0x05) // Safari Ball { if (!Legal.Inherit_Safari.Contains(species)) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4) { return(GetInvalid(V122)); } return(GetValid(V123)); } if (0x10 < ball && ball < 0x18) // Apricorn Ball { if (!Legal.Inherit_Apricorn6.Contains(species)) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4) { return(GetInvalid(V122)); } return(GetValid(V123)); } if (ball == 0x18) // Sport Ball { if (!Legal.Inherit_Sport.Contains(species)) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4) { return(GetInvalid(V122)); } return(GetValid(V123)); } if (ball == 0x19) // Dream Ball { if (pkm.AbilityNumber == 4 && Legal.Ban_DreamHidden.Contains(species)) { return(GetInvalid(V122)); } if (Legal.Inherit_Dream.Contains(species)) { return(GetValid(V123)); } return(GetInvalid(V121)); } if (0x0D <= ball && ball <= 0x0F) // Dusk Heal Quick { if (!Legal.Ban_Gen4Ball_6.Contains(species)) { return(GetValid(V123)); } return(GetInvalid(V121)); } if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked. { if (Legal.Ban_Gen3Ball.Contains(species)) { return(GetInvalid(V121)); } if (pkm.AbilityNumber == 4 && Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm)) { return(GetInvalid(V122)); } return(GetValid(V123)); } if (species > 650 && species != 700) // Sylveon { if (Legal.WildPokeballs6.Contains(pkm.Ball)) { return(GetValid(V123)); } return(GetInvalid(V121)); } return(NONE); }
private static bool UpdateIsValid(LegalityAnalysis la) { LegalityAnalyzers.Ribbon.Verify(la); return(la.Results.All(z => z.Valid)); }
private static bool TryApplyRibbon(PKM pk, LegalityAnalysis la, string rib) { SetRibbonValue(pk, rib, 1); return(UpdateIsValid(la)); }
private static bool TryRemoveRibbon(PKM pk, LegalityAnalysis la, string rib) { RemoveRibbon(pk, rib); return(UpdateIsValid(la)); }
private void updateLegality(LegalityAnalysis la = null, bool skipMoveRepop = false) { if (!fieldsLoaded) return; Legality = la ?? new LegalityAnalysis(pkm); if (!Legality.Parsed || HaX) { PB_Legal.Visible = false; return; } PB_Legal.Visible = true; PB_Legal.Image = Legality.Valid ? Resources.valid : Resources.warn; // Refresh Move Legality for (int i = 0; i < 4; i++) movePB[i].Visible = !Legality.vMoves[i].Valid && !HaX; for (int i = 0; i < 4; i++) relearnPB[i].Visible = !Legality.vRelearn[i].Valid && !HaX; if (skipMoveRepop) return; // Resort moves bool tmp = fieldsLoaded; fieldsLoaded = false; var cb = new[] {CB_Move1, CB_Move2, CB_Move3, CB_Move4 }; var moves = Legality.AllSuggestedMovesAndRelearn; var moveList = GameInfo.MoveDataSource.OrderByDescending(m => moves.Contains(m.Value)).ToList(); foreach (ComboBox c in cb) { var index = WinFormsUtil.getIndex(c); c.DataSource = new BindingSource(moveList, null); c.SelectedValue = index; } fieldsLoaded |= tmp; }
private void showLegality(PKM pk, bool tabs, bool verbose, bool skipMoveRepop = false) { LegalityAnalysis la = new LegalityAnalysis(pk); if (!la.Parsed) { WinFormsUtil.Alert($"Checking legality of PK{pk.Format} files that originated from Gen{pk.GenNumber} is not supported."); return; } if (tabs) updateLegality(la, skipMoveRepop); WinFormsUtil.Alert(verbose ? la.VerboseReport : la.Report); }
public override void Verify(LegalityAnalysis data) { VerifyMedalsRegular(data); VerifyMedalsEvent(data); }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; switch (data.EncounterMatch) { case EncounterTrade _: case MysteryGift g when !g.IsEgg: case EncounterStaticPID s when s.NSparkle: return; // already verified } var ot = pkm.OT_Name; if (ot.Length == 0) { data.AddLine(GetInvalid(V106)); } if (pkm.TID == 0 && pkm.SID == 0) { data.AddLine(Get(V33, Severity.Fishy)); } else if (pkm.VC) { if (pkm.SID != 0) { data.AddLine(GetInvalid(V34)); } } else if (pkm.TID == pkm.SID) { data.AddLine(Get(V35, Severity.Fishy)); } else if (pkm.TID == 0) { data.AddLine(Get(V36, Severity.Fishy)); } else if (pkm.SID == 0) { data.AddLine(Get(V37, Severity.Fishy)); } else if (pkm.TID == 12345 && pkm.SID == 54321 || SuspiciousOTNames.Any(z => ot.StartsWith(z))) { data.AddLine(Get(V417, Severity.Fishy)); } if (pkm.VC) { VerifyOTG1(data); } if (Legal.CheckWordFilter) { if (WordFilter.IsFiltered(ot, out string bad)) { data.AddLine(GetInvalid($"Wordfilter: {bad}")); } if (WordFilter.IsFiltered(pkm.HT_Name, out bad)) { data.AddLine(GetInvalid($"Wordfilter: {bad}")); } } }
public override void Verify(LegalityAnalysis data) { throw new Exception("Don't call via this."); }
public override void Verify(LegalityAnalysis data) { VerifyOTMemory(data); VerifyHTMemory(data); }
private void VerifySWSHStats(LegalityAnalysis data, PK8 pk8) { if (pk8.Favorite) { data.AddLine(GetInvalid(LFavoriteMarkingUnavailable, Encounter)); } var sn = pk8.StatNature; if (sn != pk8.Nature) { // Only allow Serious nature (12); disallow all other neutral natures. if (sn != 12 && (sn > 24 || sn % 6 == 0)) { data.AddLine(GetInvalid(LStatNatureInvalid)); } } var bv = pk8.BattleVersion; if (bv != 0) { if ((bv != (int)GameVersion.SW && bv != (int)GameVersion.SH) || pk8.SWSH) { data.AddLine(GetInvalid(LStatBattleVersionInvalid)); } } var enc = data.EncounterMatch; bool originGMax = enc is IGigantamax g && g.CanGigantamax; if (originGMax != pk8.CanGigantamax) { bool ok = !pk8.IsEgg && pk8.CanToggleGigantamax(pk8.Species, pk8.AltForm, enc.Species, enc.Form); var chk = ok ? GetValid(LStatGigantamaxValid) : GetInvalid(LStatGigantamaxInvalid); data.AddLine(chk); } if (pk8.DynamaxLevel != 0) { if (!pk8.CanHaveDynamaxLevel(pk8) || pk8.DynamaxLevel > 10) { data.AddLine(GetInvalid(LStatDynamaxInvalid)); } } PersonalInfo?pi = null; for (int i = 0; i < 100; i++) { if (!pk8.GetMoveRecordFlag(i)) { continue; } if ((pi ??= pk8.PersonalInfo).TMHM[i + 100]) { continue; } // Calyrex-0 can have TR flags for Calyrex-1/2 after it has force unlearned them. // Re-fusing can be reacquire the move via relearner, rather than needing another TR. // Calyrex-0 cannot reacquire the move via relearner, even though the TR is checked off in the TR list. if (pk8.Species == (int)Species.Calyrex) { var form = pk8.AltForm; // Check if another alt form can learn the TR if ((form != 1 && CanLearnTR((int)Species.Calyrex, 1, i)) || (form != 2 && CanLearnTR((int)Species.Calyrex, 2, i))) { continue; } } data.AddLine(GetInvalid(string.Format(LMoveSourceTR, ParseSettings.MoveStrings[Legal.TMHM_SWSH[i + 100]]))); } // weight/height scalars can be legally 0 (1:65536) so don't bother checking }
private void VerifyOTMemory(LegalityAnalysis data) { var pkm = data.pkm; var mem = (ITrainerMemories)pkm; var Info = data.Info; switch (data.EncounterMatch) { case WC6 { IsEgg: false } g when g.OTGender != 3 : VerifyOTMemoryIs(data, g.OT_Memory, g.OT_Intensity, g.OT_TextVar, g.OT_Feeling); return; case WC7 { IsEgg: false } g when g.OTGender != 3 : VerifyOTMemoryIs(data, g.OT_Memory, g.OT_Intensity, g.OT_TextVar, g.OT_Feeling); return; case WC8 { IsEgg: false } g when g.OTGender != 3 : VerifyOTMemoryIs(data, g.OT_Memory, g.OT_Intensity, g.OT_TextVar, g.OT_Feeling); return; case IMemoryOT t when t is not MysteryGift: // Ignore Mystery Gift cases (covered above) VerifyOTMemoryIs(data, t.OT_Memory, t.OT_Intensity, t.OT_TextVar, t.OT_Feeling); return; } int memoryGen = Info.Generation; int memory = mem.OT_Memory; if (pkm.IsEgg) { // Traded unhatched eggs in Gen8 have OT link trade memory applied erroneously. // They can also have the box-inspect memory! if (memoryGen != 8 || !((pkm.Met_Location == Locations.LinkTrade6 && memory == 4) || memory == 85)) { VerifyOTMemoryIs(data, 0, 0, 0, 0); // empty return; } } else if (!CanHaveMemoryForOT(pkm, memoryGen, memory)) { VerifyOTMemoryIs(data, 0, 0, 0, 0); // empty return; } // Bounds checking switch (memoryGen) { case 6 when pkm.XY && (memory > Memories.MAX_MEMORY_ID_XY || Memories.Memory_NotXY.Contains(memory)): case 6 when pkm.AO && (memory > Memories.MAX_MEMORY_ID_AO || Memories.Memory_NotAO.Contains(memory)): case 8 when pkm.SWSH && (memory > Memories.MAX_MEMORY_ID_SWSH || Memories.Memory_NotSWSH.Contains(memory)): data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XOT))); break; } // Verify memory if specific to OT switch (memory) { // No Memory case 0: // SWSH trades don't set HT memories immediately, which is hilarious. data.AddLine(Get(LMemoryMissingOT, memoryGen == 8 ? Severity.Fishy : Severity.Invalid)); VerifyOTMemoryIs(data, 0, 0, 0, 0); return; // {0} hatched from an Egg and saw {1} for the first time at... {2}. {4} that {3}. case 2 when !Info.EncounterMatch.EggEncounter: data.AddLine(GetInvalid(string.Format(LMemoryArgBadHatch, L_XOT))); break; // {0} became {1}’s friend when it arrived via Link Trade at... {2}. {4} that {3}. case 4 when pkm.Gen6: data.AddLine(GetInvalid(string.Format(LMemoryArgBadOTEgg, L_XOT))); return; // {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}. case 6 when memoryGen == 6 && !Memories.GetHasPokeCenterLocation((GameVersion)pkm.Version, mem.OT_TextVar): data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XOT))); return; case 6 when memoryGen == 8 && mem.OT_TextVar != 0: data.AddLine(Get(string.Format(LMemoryArgBadLocation, L_XOT), ParseSettings.Gen8MemoryLocationTextVariable)); return; // {0} was with {1} when {1} caught {2}. {4} that {3}. case 14: var result = GetCanBeCaptured(mem.OT_TextVar, Info.Generation, (GameVersion)pkm.Version) // Any Game in the Handling Trainer's generation ? GetValid(string.Format(LMemoryArgSpecies, L_XOT)) : GetInvalid(string.Format(LMemoryArgBadSpecies, L_XOT)); data.AddLine(result); return; } data.AddLine(VerifyCommonMemory(pkm, 0, Info.Generation, Info)); }
private static void VerifyTradeOTOnly(LegalityAnalysis data, EncounterTrade t) { var result = CheckTradeOTOnly(data, t.TrainerNames); data.AddLine(result); }
private void VerifyHTMemory(LegalityAnalysis data) { var pkm = data.pkm; var mem = (ITrainerMemories)pkm; var Info = data.Info; var memory = mem.HT_Memory; if (pkm.IsUntraded) { if (memory == 4 && WasTradedSWSHEgg(pkm)) { // Untraded link trade eggs in Gen8 have HT link trade memory applied erroneously. // Verify the link trade memory later. } else { VerifyHTMemoryNone(data, mem); return; } } if (pkm.Format == 7) { VerifyHTMemoryTransferTo7(data, pkm, Info); return; } var memoryGen = pkm.Format >= 8 ? 8 : 6; // Bounds checking switch (memoryGen) { case 6 when memory > Memories.MAX_MEMORY_ID_AO: case 8 when memory > Memories.MAX_MEMORY_ID_SWSH || Memories.Memory_NotSWSH.Contains(memory): data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XHT))); break; } // Verify memory if specific to HT switch (memory) { // No Memory case 0: // SWSH trades don't set HT memories immediately, which is hilarious. data.AddLine(Get(LMemoryMissingHT, memoryGen == 8 ? Severity.Fishy : Severity.Invalid)); VerifyHTMemoryNone(data, mem); return; // {0} met {1} at... {2}. {1} threw a Poké Ball at it, and they started to travel together. {4} that {3}. case 1: data.AddLine(GetInvalid(string.Format(LMemoryArgBadCatch, L_XHT))); return; // {0} hatched from an Egg and saw {1} for the first time at... {2}. {4} that {3}. case 2: data.AddLine(GetInvalid(string.Format(LMemoryArgBadHatch, L_XHT))); return; // {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}. case 6 when memoryGen == 6 && !Memories.GetHasPokeCenterLocation(GameVersion.Gen6, mem.HT_TextVar): data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XOT))); return; case 6 when memoryGen == 8 && mem.HT_TextVar != 0: data.AddLine(Get(string.Format(LMemoryArgBadLocation, L_XOT), ParseSettings.Gen8MemoryLocationTextVariable)); return; // {0} was with {1} when {1} caught {2}. {4} that {3}. case 14: var result = GetCanBeCaptured(mem.HT_TextVar, memoryGen, GameVersion.Any) // Any Game in the Handling Trainer's generation ? GetValid(string.Format(LMemoryArgSpecies, L_XHT)) : GetInvalid(string.Format(LMemoryArgBadSpecies, L_XHT)); data.AddLine(result); return; } var commonResult = VerifyCommonMemory(pkm, 1, memoryGen, Info); data.AddLine(commonResult); }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; var Info = data.Info; var EncounterMatch = data.EncounterMatch; int[] abilities = pkm.PersonalInfo.Abilities; int abilval = Array.IndexOf(abilities, pkm.Ability); if (abilval < 0) { data.AddLine(GetInvalid(V107)); return; } bool?AbilityUnchanged = true; // 3 states flag: true for unchanged, false for changed, null for uncertain/allowing PID mismatch // if true, check encounter ability // if true or false, check PID/AbilityNumber if (3 <= pkm.Format && pkm.Format <= 5 && abilities[0] != abilities[1]) // 3-5 and have 2 distinct ability now { AbilityUnchanged = VerifyAbilityPreCapsule(data, abilities, abilval); } if (EncounterMatch is PCD d) { if (VerifyAbilityPCD(data, d, AbilityUnchanged, abilities)) { return; } } else // Check Ability Mismatches { int?EncounterAbility = (EncounterMatch as EncounterStatic)?.Ability ?? (EncounterMatch as EncounterTrade)?.Ability ?? (EncounterMatch as EncounterLink)?.Ability; if (EncounterAbility != null && VerifySetAbility(data, EncounterAbility, AbilityUnchanged, abilities, abilval)) { return; // result added via VerifySetAbility } } switch (Info.Generation) { case 5: VerifyAbility5(data, abilities); break; case 6: VerifyAbility6(data, abilities); break; case 7: VerifyAbility7(data, abilities); break; } if (3 <= Info.Generation && Info.Generation <= 4 && pkm.AbilityNumber == 4) { data.AddLine(GetInvalid(V112)); } else if (AbilityUnchanged != null && abilities[pkm.AbilityNumber >> 1] != pkm.Ability) { data.AddLine(GetInvalid(pkm.Format < 6 ? V113 : V114)); } else { data.AddLine(GetValid(V115)); } }
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; if (pkm is IAwakened a) { VerifyAwakenedValues(data, a); return; } var enc = data.EncounterMatch; int sum = pkm.EVTotal; if (sum > 0 && pkm.IsEgg) { data.AddLine(GetInvalid(LEffortEgg)); } // In Generations I and II, when a Pokémon is taken out of the Day Care, its experience will lower to the minimum value for its current level. int format = pkm.Format; if (format < 3) // can abuse daycare for EV training without EXP gain { return; } if (sum > 510) // format >= 3 { data.AddLine(GetInvalid(LEffortAbove510)); } var evs = pkm.EVs; if (format >= 6 && evs.Any(ev => ev > 252)) { data.AddLine(GetInvalid(LEffortAbove252)); } const int vitaMax = 100; // Vitamin Max if (format < 5) // 3/4 { if (enc.LevelMin == 100) // only true for Gen4 and Format=4 { // Cannot EV train at level 100 -- Certain events are distributed at level 100. if (evs.Any(ev => ev > vitaMax)) // EVs can only be increased by vitamins to a max of 100. { data.AddLine(GetInvalid(LEffortCap100)); } } else // check for gained EVs without gaining EXP -- don't check gen5+ which have wings to boost above 100. { var growth = PersonalTable.HGSS[enc.Species].EXPGrowth; var baseEXP = Experience.GetEXP(enc.LevelMin, growth); if (baseEXP == pkm.EXP && evs.Any(ev => ev > vitaMax)) { data.AddLine(GetInvalid(string.Format(LEffortUntrainedCap, vitaMax))); } } } // Only one of the following can be true: 0, 508, and x%6!=0 if (sum == 0 && !enc.IsWithinRange(pkm)) { data.AddLine(Get(LEffortEXPIncreased, Severity.Fishy)); } else if (sum == 508) { data.AddLine(Get(LEffort2Remaining, Severity.Fishy)); } else if (evs[0] != 0 && evs.All(ev => evs[0] == ev)) { data.AddLine(Get(LEffortAllEqual, Severity.Fishy)); } }
private CheckResult VerifyAbility(LegalityAnalysis data) { var pkm = data.pkm; var pi = data.PersonalInfo; // Check ability is possible (within bounds) int ability = pkm.Ability; int abilIndex = pi.GetAbilityIndex(ability); if (abilIndex < 0) { return(GetInvalid(LAbilityUnexpected)); } var abilities = pi.Abilities; int format = pkm.Format; if (format >= 6) { var num = pkm.AbilityNumber; if (!IsValidAbilityBits(num)) { return(INVALID); } // Check AbilityNumber points to ability int an = num >> 1; if (an >= abilities.Count || abilities[an] != ability) { return(INVALID); } // Check AbilityNumber for transfers without unique abilities int gen = data.Info.Generation; if (gen is 3 or 4 or 5 && num != 4) { // To determine AbilityNumber [PK5->PK6], check if the first ability in Personal matches the ability. // It is not possible to flip it to the other index as capsule requires unique abilities. if (abilities[0] == abilities[1] && num != 1) { // Check if any pre-evolution could have it flipped. var evos = data.Info.EvoChainsAllGens[6]; var pt = GameData.GetPersonal(GameUtil.GetVersion(format)); if (!GetWasDual(evos, pt, pkm)) { return(INVALID); } } } } if (format >= 8) // Ability Patch { if (pkm.AbilityNumber == 4 && !pkm.LA) { if (CanAbilityPatch(format, abilities, pkm.Species)) { return(GetValid(LAbilityPatchUsed)); } var e = data.EncounterOriginal; if (e.Species != pkm.Species && CanAbilityPatch(format, PKX.Personal.GetFormEntry(e.Species, e.Form).Abilities, e.Species)) { return(GetValid(LAbilityPatchUsed)); } // Verify later, it may be encountered with its hidden ability without using an ability patch. } } var enc = data.EncounterMatch; if (enc is MysteryGift { Generation : >= 4 } g) { return(VerifyAbilityMG(data, g, abilities)); } if (format < 6) { return(VerifyAbility345(data, enc, abilities, abilIndex)); } return(VerifyAbility(data, abilities, abilIndex)); }
private void VerifySWSHStats(LegalityAnalysis data, PK8 pk8) { if (pk8.Favorite) { data.AddLine(GetInvalid(LFavoriteMarkingUnavailable, Encounter)); } var sn = pk8.StatNature; if (sn != pk8.Nature) { // Only allow Serious nature (12); disallow all other neutral natures. if (sn != 12 && (sn > 24 || sn % 6 == 0)) { data.AddLine(GetInvalid(LStatNatureInvalid)); } } var bv = pk8.BattleVersion; if (bv != 0) { if ((bv != (int)GameVersion.SW && bv != (int)GameVersion.SH) || pk8.SWSH) { data.AddLine(GetInvalid(LStatBattleVersionInvalid)); } } var enc = data.EncounterMatch; bool originGMax = enc is IGigantamax g && g.CanGigantamax; if (originGMax != pk8.CanGigantamax) { bool ok = pk8.CanToggleGigantamax(pk8.Species, pk8.AltForm, enc.Species, enc.Form); var chk = ok ? GetValid(LStatGigantamaxValid) : GetInvalid(LStatGigantamaxInvalid); data.AddLine(chk); } if (pk8.DynamaxLevel != 0) { if (!pk8.CanHaveDynamaxLevel(pk8) || pk8.DynamaxLevel > 10) { data.AddLine(GetInvalid(LStatDynamaxInvalid)); } } PersonalInfo?pi = null; for (int i = 0; i < 100; i++) { if (!pk8.GetMoveRecordFlag(i)) { continue; } if (!(pi ??= pk8.PersonalInfo).TMHM[i + 100]) { data.AddLine(GetInvalid(string.Format(LMoveSourceTR, LegalityAnalysis.MoveStrings[Legal.TMHM_SWSH[i + 100]]))); } } // weight/height scalars can be legally 0 (1:65536) so don't bother checking }
private CheckResult VerifyBallEggGen7(LegalityAnalysis data) { var pkm = data.pkm; int species = data.EncounterMatch.Species; if (722 <= species && species <= 730) // G7 Starters { return(VerifyBallEquals(data, (int)Poke)); } Ball ball = (Ball)pkm.Ball; if (ball == Safari) { if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species))) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4 && Legal.Ban_SafariBallHidden_7.Contains(species)) { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (ball.IsApricornBall()) // Apricorn Ball { if (!Legal.Inherit_Apricorn7.Contains(species)) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden7Apricorn.Contains(species | pkm.AltForm << 11)) // lineage is 3->2->origin { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (ball == Sport) // Sport Ball { if (!Legal.Inherit_Sport.Contains(species)) { return(GetInvalid(LBallSpecies)); } if (pkm.AbilityNumber == 4 && (species == 313 || species == 314)) // Volbeat/Illumise { return(GetInvalid(LBallAbility)); } return(GetValid(LBallSpeciesPass)); } if (ball == Dream) // Dream Ball { if (Legal.Inherit_Dream.Contains(species) || Legal.Inherit_DreamMale.Contains(species)) { return(GetValid(LBallSpeciesPass)); } return(GetInvalid(LBallSpecies)); } if (Dusk <= ball && ball <= Quick) // Dusk Heal Quick { if (!Legal.Ban_Gen4Ball_7.Contains(species)) { return(GetValid(LBallSpeciesPass)); } return(GetInvalid(LBallSpecies)); } if (Ultra <= ball && ball <= Premier) // Don't worry, Safari was already checked. { if (!Legal.Ban_Gen3Ball_7.Contains(species)) { return(GetValid(LBallSpeciesPass)); } return(GetInvalid(LBallSpecies)); } if (ball == Beast) { if (species == 669 && pkm.AltForm == 3 && pkm.AbilityNumber == 4) { return(GetInvalid(LBallAbility)); // Can't obtain Flabébé-Blue with Hidden Ability in wild } if ((species > 731 && species <= 785) || (Legal.AlolanCaptureOffspring.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species))) { return(GetValid(LBallSpeciesPass)); } if (Legal.PastGenAlolanScans.Contains(species)) { return(GetValid(LBallSpeciesPass)); } // next statement catches all new alolans } if (species > 721) { return(VerifyBallEquals(data, Legal.WildPokeballs7)); } if (ball > Beast) { return(GetInvalid(LBallUnavailable)); } return(NONE); }
public override void Verify(LegalityAnalysis data) { throw new NotImplementedException(); }
private CheckResult VerifyBallEquals(LegalityAnalysis data, ICollection <int> balls) => GetResult(balls.Contains(data.pkm.Ball));
private CheckResult VerifyForm(LegalityAnalysis data) { var pkm = data.pkm; var PersonalInfo = data.PersonalInfo; int count = PersonalInfo.FormCount; var form = pkm.Form; if (count <= 1 && form == 0) { return(VALID); // no forms to check } var species = pkm.Species; var enc = data.EncounterMatch; var Info = data.Info; if (!PersonalInfo.IsFormWithinRange(form) && !FormInfo.IsValidOutOfBoundsForm(species, form, Info.Generation)) { return(GetInvalid(string.Format(LFormInvalidRange, count - 1, form))); } switch (enc) { case EncounterSlot w when w.Area.Type == SlotType.FriendSafari: VerifyFormFriendSafari(data); break; case EncounterEgg e when FormInfo.IsTotemForm(species, form, e.Generation): return(GetInvalid(LFormInvalidGame)); } switch ((Species)species) { case Pikachu when Info.Generation == 6: // Cosplay bool isStatic = enc is EncounterStatic; bool validCosplay = form == (isStatic ? enc.Form : 0); if (!validCosplay) { return(GetInvalid(isStatic ? LFormPikachuCosplayInvalid : LFormPikachuCosplay)); } break; case Pikachu when Info.Generation >= 7: // Cap bool validCap = form == (enc is EncounterInvalid ? 0 : enc.Form); if (!validCap) { bool gift = enc is MysteryGift g && g.Form != form; var msg = gift ? LFormPikachuEventInvalid : LFormInvalidGame; return(GetInvalid(msg)); } break; case Unown when Info.Generation == 2 && form >= 26: return(GetInvalid(string.Format(LFormInvalidRange, "Z", form == 26 ? "!" : "?"))); case Giratina when form == 1 ^ pkm.HeldItem == 112: // Giratina, Origin form only with Griseous Orb return(GetInvalid(LFormItemInvalid)); case Arceus: { int arceus = GetArceusFormFromHeldItem(pkm.HeldItem, pkm.Format); return(arceus != form?GetInvalid(LFormItemInvalid) : GetValid(LFormItem)); } case Keldeo when pkm.Format < 8 && enc.Generation != 5: // can mismatch in gen5 via BW tutor and transfer up // can mismatch in gen8+ as the form activates in battle when knowing the move; outside of battle can be either state. bool hasSword = pkm.HasMove((int)Move.SecretSword); bool isSword = pkm.Form == 1; if (isSword != hasSword) { return(GetInvalid(LMoveKeldeoMismatch)); } break; case Genesect: { int genesect = GetGenesectFormFromHeldItem(pkm.HeldItem); return(genesect != form?GetInvalid(LFormItemInvalid) : GetValid(LFormItem)); } case Greninja: if (form > 1) // Ash Battle Bond active { return(GetInvalid(LFormBattle)); } if (form != 0 && enc is not MysteryGift) // Formes are not breedable, MysteryGift already checked { return(GetInvalid(string.Format(LFormInvalidRange, 0, form))); } break; case Scatterbug or Spewpa: if (form > 17) // Fancy & Pokéball { return(GetInvalid(LFormVivillonEventPre)); } if (pkm is not IRegionOrigin tr) { break; } if (!Vivillon3DS.IsPatternValid(form, (byte)tr.Country, (byte)tr.Region)) { data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy)); } break; case Vivillon: if (form > 17) // Fancy & Pokéball { if (enc is not MysteryGift) { return(GetInvalid(LFormVivillonInvalid)); } return(GetValid(LFormVivillon)); } if (pkm is not IRegionOrigin trv) { break; } if (!Vivillon3DS.IsPatternValid(form, (byte)trv.Country, (byte)trv.Region)) { data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy)); } break; case Floette when form == 5: // Floette Eternal Flower -- Never Released if (enc is not MysteryGift) { return(GetInvalid(LFormEternalInvalid)); } return(GetValid(LFormEternal)); case Meowstic when form != pkm.Gender: return(GetInvalid(LGenderInvalidNone)); case Silvally: { int silvally = GetSilvallyFormFromHeldItem(pkm.HeldItem); return(silvally != form?GetInvalid(LFormItemInvalid) : GetValid(LFormItem)); } // Form doesn't exist in SM; cannot originate from that game. case Lillipup when enc.Generation == 7 && form == 1 && pkm.SM: case Lycanroc when enc.Generation == 7 && form == 2 && pkm.SM: return(GetInvalid(LFormInvalidGame)); // Toxel encounters have already been checked for the nature-specific evolution criteria. case Toxtricity when enc.Species == (int)Toxtricity: { // The game enforces the Nature for Toxtricity encounters too! if (pkm.Form != EvolutionMethod.GetAmpLowKeyResult(pkm.Nature)) { return(GetInvalid(LFormInvalidNature)); } break; } // Impossible Egg forms case Rotom when pkm.IsEgg && form != 0: case Furfrou when pkm.IsEgg && form != 0: return(GetInvalid(LEggSpecies)); // Party Only Forms case Shaymin: case Furfrou: case Hoopa: if (form != 0 && pkm.Box > -1 && pkm.Format <= 6) // has form but stored in box { return(GetInvalid(LFormParty)); } break; } var format = pkm.Format; if (FormInfo.IsBattleOnlyForm(species, form, format)) { return(GetInvalid(LFormBattle)); } if (form == 0) { return(VALID); } // everything below here is not Form 0, so it has a form. if (format >= 7 && Info.Generation < 7) { if (species == 25 || Legal.AlolanOriginForms.Contains(species) || Legal.AlolanVariantEvolutions12.Contains(enc.Species)) { return(GetInvalid(LFormInvalidGame)); } } if (format >= 8 && Info.Generation < 8) { var orig = enc.Species; if (Legal.GalarOriginForms.Contains(species) || Legal.GalarVariantFormEvolutions.Contains(orig)) { if (species == (int)Meowth && enc.Form != 2) { // We're okay here. There's also Alolan Meowth... } else if (((Species)orig is MrMime or MimeJr) && pkm.CurrentLevel > enc.LevelMin && Info.Generation >= 4) { // We're okay with a Mime Jr. that has evolved via level up. } else if (enc.Version != GameVersion.GO) { return(GetInvalid(LFormInvalidGame)); } } }