public override void Verify(LegalityAnalysis data) { if (data.Entity is not IGroundTile e) { return; } var type = data.EncounterMatch is IGroundTypeTile t ? t.GroundTile : GroundTileAllowed.None; var result = !type.Contains(e.GroundTile) ? GetInvalid(LEncTypeMismatch) : GetValid(LEncTypeMatch); data.AddLine(result); }
/// <summary> /// Used for enforcing a fixed memory detail. /// </summary> /// <param name="data">Output storage</param> /// <param name="m">Memory ID</param> /// <param name="i">Intensity</param> /// <param name="t">Text Variable</param> /// <param name="f">Feeling</param> private void VerifyOTMemoryIs(LegalityAnalysis data, byte m, byte i, ushort t, byte f) { var pk = (ITrainerMemories)data.Entity; if (pk.OT_Memory != m) { data.AddLine(GetInvalid(string.Format(LMemoryIndexID, L_XOT, m))); } if (pk.OT_Intensity != i) { data.AddLine(GetInvalid(string.Format(LMemoryIndexIntensity, L_XOT, i))); } if (pk.OT_TextVar != t) { data.AddLine(GetInvalid(string.Format(LMemoryIndexVar, L_XOT, t))); } if (pk.OT_Feeling != f) { data.AddLine(GetInvalid(string.Format(LMemoryIndexFeel, L_XOT, f))); } }
private void VerifyAwakenedValues(LegalityAnalysis data, IAwakened awakened) { var pk = data.Entity; int sum = pk.EVTotal; if (sum != 0) { data.AddLine(GetInvalid(LEffortShouldBeZero)); } if (!awakened.AwakeningAllValid()) { data.AddLine(GetInvalid(LAwakenedCap)); } var enc = data.EncounterMatch; // go park transfers have 2 AVs for all stats. if (enc is EncounterSlot7GO) { Span <byte> avs = stackalloc byte[6]; awakened.GetAVs(avs); foreach (var av in avs) { if (av >= 2) { continue; } data.AddLine(GetInvalid(string.Format(LAwakenedShouldBeValue, 2))); break; } return; } if (awakened.AwakeningSum() == 0 && !enc.IsWithinEncounterRange(pk)) { data.AddLine(Get(LAwakenedEXPIncreased, Severity.Fishy)); } }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; // If the Pokémon is not nicknamed, it should match one of the language strings. var nickname = pk.Nickname; if (nickname.Length == 0) { data.AddLine(GetInvalid(LNickLengthShort)); return; } if (pk.Species > SpeciesName.SpeciesLang[0].Count) { data.AddLine(Get(LNickLengthShort, Severity.Indeterminate)); return; } var enc = data.EncounterOriginal; if (enc is ILangNicknamedTemplate n) { VerifyFixedNicknameEncounter(data, n, enc, pk, nickname); if (pk.IsEgg) { VerifyNicknameEgg(data); } return; } if (pk.Format <= 7 && pk.IsNicknamed) // can nickname afterwards { if (pk.VC) { VerifyG1NicknameWithinBounds(data, nickname.AsSpan()); } else if (enc is MysteryGift { IsEgg : false })
private void VerifyHTMemoryTransferTo7(LegalityAnalysis data, PKM pk, LegalInfo Info) { var mem = (ITrainerMemories)pk; // Bank Transfer adds in the Link Trade Memory. // Trading 7<->7 between games (not Bank) clears this data. if (mem.HT_Memory == 0) { VerifyHTMemoryNone(data, mem); 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 (gen is >= 3 and < 7 && pk.CurrentHandler == 1) { return; } if (mem.HT_Memory != 4) { data.AddLine(Severity.Invalid, LMemoryIndexLinkHT, CheckIdentifier.Memory); } if (mem.HT_TextVar != 0) { data.AddLine(Severity.Invalid, LMemoryIndexArgHT, CheckIdentifier.Memory); } if (mem.HT_Intensity != 1) { data.AddLine(Severity.Invalid, LMemoryIndexIntensityHT1, CheckIdentifier.Memory); } if (mem.HT_Feeling > 10) { data.AddLine(Severity.Invalid, LMemoryIndexFeelHT09, CheckIdentifier.Memory); } }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; var pi = pk.PersonalInfo; if (pi.Genderless != (pk.Gender == 2)) { // DP/HGSS shedinja glitch -- only generation 4 spawns bool ignore = pk.Format == 4 && pk.Species == (int)Species.Shedinja && pk.Met_Level != pk.CurrentLevel; if (!ignore) { data.AddLine(GetInvalid(LGenderInvalidNone)); } return; } // Check for PID relationship to Gender & Nature if applicable int gen = data.Info.Generation; if (gen is 3 or 4 or 5) { // Gender-PID & Nature-PID relationship check var result = IsValidGenderPID(data) ? GetValid(LPIDGenderMatch) : GetInvalid(LPIDGenderMismatch); data.AddLine(result); if (gen != 5) { VerifyNaturePID(data); } return; } // Check fixed gender cases if ((pi.OnlyFemale && pk.Gender != 1) || (pi.OnlyMale && pk.Gender != 0)) { data.AddLine(GetInvalid(LGenderInvalidNone)); } }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; if (!TrainerNameVerifier.IsPlayerOriginalTrainer(data.EncounterMatch)) { return; // already verified } if (pk.BDSP) { if (pk.TID == 0 && pk.SID == 0) // Game loops to ensure a nonzero full-ID { data.AddLine(GetInvalid(LOT_IDInvalid)); return; } if (pk.TID == 0xFFFF && pk.SID == 0x7FFF) // int.MaxValue cannot be yielded by Unity's Random.Range[min, max) { data.AddLine(GetInvalid(LOT_IDInvalid)); return; } } else if (pk.VC && pk.SID != 0) { data.AddLine(GetInvalid(LOT_SID0Invalid)); return; } if (pk.TID == 0 && pk.SID == 0) { data.AddLine(Get(LOT_IDs0, Severity.Fishy)); } else if (pk.TID == pk.SID) { data.AddLine(Get(LOT_IDEqual, Severity.Fishy)); } else if (pk.TID == 0) { data.AddLine(Get(LOT_TID0, Severity.Fishy)); } else if (pk.SID == 0) { data.AddLine(Get(LOT_SID0, Severity.Fishy)); } else if (IsOTIDSuspicious(pk.TID, pk.SID)) { data.AddLine(Get(LOTSuspicious, Severity.Fishy)); } }
public override void Verify(LegalityAnalysis data) { if (data.Entity is not PA8 pa) { return; } if (pa.IsNoble) { data.AddLine(GetInvalid(LStatNobleInvalid)); } if (pa.IsAlpha != data.EncounterMatch is IAlpha { IsAlpha : true })
public override void Verify(LegalityAnalysis data) { var pkm = data.pkm; if (pkm.Format <= 4) { return; // legal || not present } if (pkm is IContestStats s && s.HasContestStats() && !CanHaveContestStats(pkm, s, data.Info.Generation)) { data.AddLine(GetInvalid(LegalityCheckStrings.LContestZero)); } // some encounters have contest stats built in. they're already checked by the initial encounter match. }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; int originalGeneration = data.Info.Generation; int currentLanguage = pk.Language; int maxLanguageID = Legal.GetMaxLanguageID(originalGeneration); var enc = data.EncounterMatch; if (!IsValidLanguageID(currentLanguage, maxLanguageID, pk, enc)) { data.AddLine(GetInvalid(string.Format(LOTLanguage, $"<={(LanguageID)maxLanguageID}", (LanguageID)currentLanguage))); return; } // Korean Gen4 games can not trade with other Gen4 languages, but can use Pal Park with any Gen3 game/language. if (pk.Format == 4 && enc.Generation == 4 && !IsValidG4Korean(currentLanguage) && enc is not EncounterTrade4PID { Species : (int)Species.Pikachu or(int) Species.Magikarp } // ger magikarp / eng pikachu
public override void Verify(LegalityAnalysis data) { var pk = data.pkm; if (!pk.LA || pk is not PA8 pa) { return; } CheckLearnset(data, pa); CheckMastery(data, pa); if (pa.IsNoble) { data.AddLine(GetInvalid(LStatNobleInvalid)); } if (pa.IsAlpha != data.EncounterMatch is IAlpha { IsAlpha : true })
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; var enc = data.EncounterMatch; if (!IsPlayerOriginalTrainer(enc)) { return; // already verified } var ot = pk.OT_Name; if (ot.Length == 0) { data.AddLine(GetInvalid(LOTShort)); } if (IsOTNameSuspicious(ot)) { data.AddLine(Get(LOTSuspicious, Severity.Fishy)); } if (pk.VC) { VerifyOTG1(data); } else if (ot.Length > Legal.GetMaxLengthOT(data.Info.Generation, (LanguageID)pk.Language)) { if (!IsEdgeCaseLength(pk, 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 (ContainsTooManyNumbers(ot, data.Info.Generation)) { data.AddLine(GetInvalid("Wordfilter: Too many numbers.")); } if (WordFilter.IsFiltered(pk.HT_Name, out bad)) { data.AddLine(GetInvalid($"Wordfilter: {bad}")); } } }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; bool checksRequired = data.EncounterMatch is EncounterStatic5N; if (pk is PK5 pk5) { bool has = pk5.NSparkle; if (checksRequired && !has) { data.AddLine(GetInvalid(LG5SparkleRequired, CheckIdentifier.Fateful)); } if (!checksRequired && has) { data.AddLine(GetInvalid(LG5SparkleInvalid, CheckIdentifier.Fateful)); } } if (!checksRequired) { return; } if (pk.OT_Gender != 0) { data.AddLine(GetInvalid(LG5OTGenderN, CheckIdentifier.Trainer)); } if (pk.IVTotal != 30 * 6) { data.AddLine(GetInvalid(LG5IVAll30, CheckIdentifier.IVs)); } if (!VerifyNsPKMOTValid(pk)) { data.AddLine(GetInvalid(LG5ID_N, CheckIdentifier.Trainer)); } if (pk.IsShiny) { data.AddLine(GetInvalid(LG5PIDShinyN, CheckIdentifier.Shiny)); } }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; if (pk is IAwakened a) { VerifyAwakenedValues(data, a); return; } var enc = data.EncounterMatch; if (pk.IsEgg) { if (pk.EVTotal is not 0) { data.AddLine(GetInvalid(LEffortEgg)); } return; } // 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 = pk.Format; if (format < 3) // can abuse daycare for EV training without EXP gain { return; } int sum = pk.EVTotal; if (sum > 510) // format >= 3 { data.AddLine(GetInvalid(LEffortAbove510)); } Span <int> evs = stackalloc int[6]; pk.GetEVs(evs); if (format >= 6 && evs.Find(ev => ev > 252) != default) { 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.Find(ev => ev > vitaMax) != default) // 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 == pk.EXP && evs.Find(ev => ev > vitaMax) != default) { 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.IsWithinEncounterRange(pk)) { data.AddLine(Get(LEffortEXPIncreased, Severity.Fishy)); } else if (sum == 508) { data.AddLine(Get(LEffort2Remaining, Severity.Fishy)); } else if (evs[0] != 0 && evs.Count(evs[0]) == evs.Length) { data.AddLine(Get(LEffortAllEqual, Severity.Fishy)); } }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; var enc = data.EncounterOriginal; if (enc is MysteryGift gift) { if (gift.Level != pk.Met_Level && pk.HasOriginalMetLocation) { switch (gift) { case WC3 wc3 when wc3.Met_Level == pk.Met_Level || wc3.IsEgg: break; case WC7 wc7 when wc7.MetLevel == pk.Met_Level: break; case PGT { IsManaphyEgg: true } when pk.Met_Level == 0 : break; default: data.AddLine(GetInvalid(LLevelMetGift)); return; } } if (gift.Level > pk.CurrentLevel) { data.AddLine(GetInvalid(LLevelMetGiftFail)); return; } } if (pk.IsEgg) { int elvl = enc.LevelMin; if (elvl != pk.CurrentLevel) { data.AddLine(GetInvalid(string.Format(LEggFMetLevel_0, elvl))); return; } var reqEXP = enc is EncounterStatic2Odd ? 125 // Gen2 Dizzy Punch gifts always have 125 EXP, even if it's more than the Lv5 exp required. : Experience.GetEXP(elvl, pk.PersonalInfo.EXPGrowth); if (reqEXP != pk.EXP) { data.AddLine(GetInvalid(LEggEXP)); } return; } int lvl = pk.CurrentLevel; if (lvl >= 100) { var expect = Experience.GetEXP(100, pk.PersonalInfo.EXPGrowth); if (pk.EXP != expect) { data.AddLine(GetInvalid(LLevelEXPTooHigh)); } } if (lvl < pk.Met_Level) { data.AddLine(GetInvalid(LLevelMetBelow)); } else if (!enc.IsWithinEncounterRange(pk) && lvl != 100 && pk.EXP == Experience.GetEXP(lvl, pk.PersonalInfo.EXPGrowth)) { data.AddLine(Get(LLevelEXPThreshold, Severity.Fishy)); } else { data.AddLine(GetValid(LLevelMetSane)); } }
private void VerifyMedalsRegular(LegalityAnalysis data) { var pk = data.Entity; var train = (ISuperTrain)pk; var Info = data.Info; uint value = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(data.Entity.Data.AsSpan(0x2C)); if ((value & 3) != 0) // 2 unused flags { data.AddLine(GetInvalid(LSuperUnused)); } int TrainCount = train.SuperTrainingMedalCount(); if (pk.IsEgg) { // Can't have any super training data as an egg. if (TrainCount > 0) { data.AddLine(GetInvalid(LSuperEgg)); } if (train.SecretSuperTrainingUnlocked) { data.AddLine(GetInvalid(LSuperNoUnlocked)); } if (train.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperNoComplete)); } return; } if (Info.Generation is >= 7 or <= 2) { // Can't have any super training data if it never visited Gen6. if (TrainCount > 0) { data.AddLine(GetInvalid(LSuperUnavailable)); } if (train.SecretSuperTrainingUnlocked) { data.AddLine(GetInvalid(LSuperNoUnlocked)); } if (train.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperNoComplete)); } return; } if (pk.Format >= 7) { // Gen6->Gen7 transfer wipes the two Secret flags. if (train.SecretSuperTrainingUnlocked) { data.AddLine(GetInvalid(LSuperNoUnlocked)); } if (train.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperNoComplete)); } return; } // Only reach here if Format==6. if (TrainCount == 30 ^ train.SecretSuperTrainingComplete) { data.AddLine(GetInvalid(LSuperComplete)); } }
private void VerifyOTMemory(LegalityAnalysis data) { var pk = data.Entity; var mem = (ITrainerMemories)pk; var Info = data.Info; // If the encounter has a memory from the OT that could never have it replaced, ensure it was not modified. 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 and 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; var memory = mem.OT_Memory; if (pk.IsEgg) { // Traded unhatched eggs in Gen8 have OT link trade memory applied erroneously. // They can also have the box-inspect memory! if (memoryGen != 8 || !((pk.Met_Location == Locations.LinkTrade6 && memory == 4) || memory == 85)) { VerifyOTMemoryIs(data, 0, 0, 0, 0); // empty return; } } else if (!CanHaveMemoryForOT(pk, memoryGen, memory, Info.EvoChainsAllGens)) { VerifyOTMemoryIs(data, 0, 0, 0, 0); // empty return; } // Bounds checking var context = Memories.GetContext(memoryGen); if (!context.CanObtainMemoryOT((GameVersion)pk.Version, memory)) { data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XOT))); } // 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 Info.Generation == 6: // gen8 applies this memory erroneously 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 !context.HasPokeCenter((GameVersion)pk.Version, mem.OT_TextVar): data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XOT))); return; // {0} was with {1} when {1} caught {2}. {4} that {3}. case 14: var result = GetCanBeCaptured(mem.OT_TextVar, Info.Generation, (GameVersion)pk.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(pk, 0, Info.Generation, Info, context)); }
private void VerifyHTMemory(LegalityAnalysis data) { var pk = data.Entity; var mem = (ITrainerMemories)pk; var Info = data.Info; var memory = mem.HT_Memory; if (pk.IsUntraded) { if (memory == 4 && WasTradedSWSHEgg(pk)) { // 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 (pk.Format == 7) { VerifyHTMemoryTransferTo7(data, pk, Info); return; } var memoryGen = pk.Format >= 8 ? 8 : 6; // Bounds checking var context = Memories.GetContext(memoryGen); if (!context.CanObtainMemoryHT((GameVersion)pk.Version, memory)) { data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XHT))); } // Verify memory if specific to HT switch (memory) { // No Memory case 0: // SWSH memory application has an off-by-one error: [0,99] + 1 <= chance --> don't apply data.AddLine(Get(LMemoryMissingHT, memoryGen == 8 ? ParseSettings.Gen8MemoryMissingHT : 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 !context.HasPokeCenter(GameVersion.Any, mem.HT_TextVar): data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XHT))); 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(pk, 1, memoryGen, Info, context); data.AddLine(commonResult); }
public override void Verify(LegalityAnalysis data) { var pk = data.Entity; if (pk is not IContestStats s) { return; } // If no stats have been increased from the initial amount, then we're done here. // some encounters have contest stats built in. they're already checked by the initial encounter match. if (!s.HasContestStats()) { return; } // Check the correlation of Stats & Sheen! // In generations 3,4 and BDSP, blocks/poffins have a feel(sheen) equal to sheen=sum(stats)/5, with +/- 10% for a favored stat. // In generation 6 (ORAS), they don't award any sheen, so any value is legal. var correlation = GetContestStatRestriction(pk, data.Info.Generation, data.Info.EvoChainsAllGens); if (correlation == None) { // We're only here because we have contest stat values. We aren't permitted to have any, so flag it. data.AddLine(GetInvalid(LContestZero)); } else if (correlation == NoSheen) { // We can get contest stat values, but we can't get any for Sheen. // Any combination of non-sheen is ok, but nonzero sheen is illegal. if (s.CNT_Sheen != 0) { data.AddLine(GetInvalid(LContestZeroSheen)); } } else if (correlation == CorrelateSheen) { bool gen3 = data.Info.Generation == 3; bool bdsp = pk.HasVisitedBDSP(data.Info.EvoChainsAllGens.Gen8b); var method = gen3 ? ContestStatGrantingSheen.Gen3 : bdsp ? ContestStatGrantingSheen.Gen8b : ContestStatGrantingSheen.Gen4; // Check for stat values that exceed a valid sheen value. var initial = GetReferenceTemplate(data.Info.EncounterMatch); var minSheen = CalculateMinimumSheen(s, initial, pk, method); if (s.CNT_Sheen < minSheen) { data.AddLine(GetInvalid(string.Format(LContestSheenTooLow_0, minSheen))); } // Check for sheen values that are too high. var maxSheen = CalculateMaximumSheen(s, pk.Nature, initial, gen3); if (s.CNT_Sheen > maxSheen) { data.AddLine(GetInvalid(string.Format(LContestSheenTooHigh_0, maxSheen))); } } else if (correlation == Mixed) { bool gen3 = data.Info.Generation == 3; // Check for sheen values that are too high. var initial = GetReferenceTemplate(data.Info.EncounterMatch); var maxSheen = CalculateMaximumSheen(s, pk.Nature, initial, gen3); if (s.CNT_Sheen > maxSheen) { data.AddLine(GetInvalid(string.Format(LContestSheenTooHigh_0, maxSheen))); } } }
public override void Verify(LegalityAnalysis data) { var result = VerifyAbility(data); data.AddLine(result); }