using System.Linq; using static PKHeX.Core.LegalityCheckStrings; namespace PKHeX.Core { /// /// Verifies the . /// public sealed class TrainerNameVerifier : Verifier { protected override CheckIdentifier Identifier => CheckIdentifier.Trainer; private readonly string[] SuspiciousOTNames = { "PKHeX", }; 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(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.GetNicknameOTMaxLength(data.Info.Generation, (LanguageID)pkm.Language)) { if (!pkm.IsEgg) // ignore eggs, on trade, OT is not updated if language is data.AddLine(Get(LOTLong, data.EncounterOriginal.EggEncounter ? Severity.Fishy : 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}")); } } public void VerifyOTG1(LegalityAnalysis data) { var pkm = data.pkm; string tr = pkm.OT_Name; VerifyG1OTWithinBounds(data, tr); if (data.EncounterOriginal is EncounterStatic s && (s.Version == GameVersion.Stadium || s.Version == GameVersion.Stadium2)) data.AddLine(VerifyG1OTStadium(pkm, tr, s)); if (pkm.Species == 151) { var OTMatch = (tr == Legal.GetG1OT_GFMew((int)LanguageID.Japanese)) || (tr == Legal.GetG1OT_GFMew((int)LanguageID.English)); if (!OTMatch || pkm.TID != 22796) data.AddLine(GetInvalid(LG1OTEvent)); } if (pkm.OT_Gender == 1 && ((pkm.Format == 2 && pkm.Met_Location == 0) || (pkm.Format > 2 && pkm.VC1))) data.AddLine(GetInvalid(LG1OTGender)); } private void VerifyG1OTWithinBounds(LegalityAnalysis data, string str) { if (StringConverter.GetIsG1English(str)) { if (str.Length > 7 && !(data.EncounterOriginal is EncounterTrade)) // OT already verified; GER shuckle has 8 chars data.AddLine(GetInvalid(LOTLong)); } else if (StringConverter.GetIsG1Japanese(str)) { if (str.Length > 5) data.AddLine(GetInvalid(LOTLong)); } else if (data.pkm.Korean && StringConverter.GetIsG2Korean(str)) { if (str.Length > 5) data.AddLine(GetInvalid(LOTLong)); } else { data.AddLine(GetInvalid(LG1CharOT)); } } private CheckResult VerifyG1OTStadium(PKM pkm, string tr, IVersion s) { bool jp = pkm.Japanese; var ot = Legal.GetGBStadiumOTName(jp, s.Version); var id = Legal.GetGBStadiumOTID(jp, s.Version); bool valid = ot == tr && id == pkm.TID; return valid ? GetValid(jp ? LG1StadiumJapanese : LG1StadiumInternational) : GetInvalid(LG1Stadium); } private bool IsOTNameSuspicious(string name) { return SuspiciousOTNames.Any(name.StartsWith); } } }