2018-07-27 02:34:27 +00:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
namespace PKHeX.Core
|
|
|
|
|
{
|
2018-07-02 02:17:37 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Verifies the <see cref="PKM.OT_Name"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class TrainerNameVerifier : Verifier
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
protected override CheckIdentifier Identifier => CheckIdentifier.Trainer;
|
|
|
|
|
|
2020-08-31 02:59:21 +00:00
|
|
|
|
private static readonly string[] SuspiciousOTNames =
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
"PKHeX",
|
2020-10-04 15:59:33 +00:00
|
|
|
|
"PKHeX",
|
2018-06-24 05:00:01 +00:00
|
|
|
|
};
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
public override void Verify(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
|
|
|
|
switch (data.EncounterMatch)
|
|
|
|
|
{
|
|
|
|
|
case EncounterTrade _:
|
|
|
|
|
case MysteryGift g when !g.IsEgg:
|
2020-01-25 20:31:56 +00:00
|
|
|
|
case EncounterStatic5N _:
|
2018-06-24 05:00:01 +00:00
|
|
|
|
return; // already verified
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ot = pkm.OT_Name;
|
|
|
|
|
if (ot.Length == 0)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LOTShort));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
if (pkm.TID == 0 && pkm.SID == 0)
|
2018-07-27 02:34:27 +00:00
|
|
|
|
{
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(Get(LOT_IDs0, Severity.Fishy));
|
2018-07-27 02:34:27 +00:00
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
else if (pkm.VC)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.SID != 0)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LOT_SID0Invalid));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
else if (pkm.TID == pkm.SID)
|
2018-07-27 02:34:27 +00:00
|
|
|
|
{
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(Get(LOT_IDEqual, Severity.Fishy));
|
2018-07-27 02:34:27 +00:00
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
else if (pkm.TID == 0)
|
2018-07-27 02:34:27 +00:00
|
|
|
|
{
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(Get(LOT_TID0, Severity.Fishy));
|
2018-07-27 02:34:27 +00:00
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
else if (pkm.SID == 0)
|
2018-07-27 02:34:27 +00:00
|
|
|
|
{
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(Get(LOT_SID0, Severity.Fishy));
|
2018-07-27 02:34:27 +00:00
|
|
|
|
}
|
2020-08-31 02:59:21 +00:00
|
|
|
|
else if (IsOTNameSuspicious(ot))
|
|
|
|
|
{
|
|
|
|
|
data.AddLine(Get(LOTSuspicious, Severity.Fishy));
|
|
|
|
|
}
|
|
|
|
|
else if (IsOTIDSuspicious(pkm.TID, pkm.SID))
|
2018-07-27 02:34:27 +00:00
|
|
|
|
{
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(Get(LOTSuspicious, Severity.Fishy));
|
2018-07-27 02:34:27 +00:00
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
if (pkm.VC)
|
2018-08-17 03:06:40 +00:00
|
|
|
|
{
|
2018-06-24 05:00:01 +00:00
|
|
|
|
VerifyOTG1(data);
|
2018-08-17 03:06:40 +00:00
|
|
|
|
}
|
2018-10-27 23:06:06 +00:00
|
|
|
|
else if (ot.Length > Legal.GetMaxLengthOT(data.Info.Generation, (LanguageID)pkm.Language))
|
2018-08-15 22:19:54 +00:00
|
|
|
|
{
|
2018-10-27 23:06:06 +00:00
|
|
|
|
if (!IsEdgeCaseLength(pkm, data.EncounterOriginal, ot))
|
|
|
|
|
data.AddLine(Get(LOTLong, Severity.Invalid));
|
2018-08-15 22:19:54 +00:00
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-10-06 02:58:30 +00:00
|
|
|
|
if (ParseSettings.CheckWordFilter)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
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}"));
|
2018-10-09 00:57:34 +00:00
|
|
|
|
if (ContainsTooManyNumbers(ot, data.Info.Generation))
|
2020-06-28 04:36:53 +00:00
|
|
|
|
data.AddLine(GetInvalid("Wordfilter: Too many numbers."));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-10-27 23:06:06 +00:00
|
|
|
|
public static bool IsEdgeCaseLength(PKM pkm, IEncounterable e, string ot)
|
|
|
|
|
{
|
|
|
|
|
if (e.EggEncounter)
|
|
|
|
|
{
|
2018-11-03 19:44:03 +00:00
|
|
|
|
if (e is WC3 wc3 && pkm.IsEgg && wc3.OT_Name == ot)
|
|
|
|
|
return true; // Fixed OT Mystery Gift Egg
|
2018-12-15 07:30:21 +00:00
|
|
|
|
bool eggEdge = pkm.IsEgg ? pkm.IsTradedEgg || pkm.Format == 3 : pkm.WasTradedEgg;
|
2018-10-27 23:06:06 +00:00
|
|
|
|
if (!eggEdge)
|
|
|
|
|
return false;
|
2020-05-31 19:12:48 +00:00
|
|
|
|
var len = Legal.GetMaxLengthOT(e.Generation, LanguageID.English); // max case
|
2018-10-27 23:06:06 +00:00
|
|
|
|
return ot.Length <= len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e is MysteryGift mg && mg.OT_Name.Length == ot.Length)
|
|
|
|
|
return true; // Mattle Ho-Oh
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
public void VerifyOTG1(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
|
|
|
|
string tr = pkm.OT_Name;
|
|
|
|
|
|
2020-09-10 05:43:32 +00:00
|
|
|
|
if (tr.Length == 0)
|
|
|
|
|
{
|
2020-10-04 04:56:57 +00:00
|
|
|
|
if (pkm is SK2 sk2 && sk2.OT_Trash[0] == 0)
|
|
|
|
|
{
|
|
|
|
|
data.AddLine(Get(LOTShort, Severity.Fishy));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
data.AddLine(GetInvalid(LOTShort));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-10 05:43:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
VerifyG1OTWithinBounds(data, tr);
|
|
|
|
|
if (data.EncounterOriginal is EncounterStatic s && (s.Version == GameVersion.Stadium || s.Version == GameVersion.Stadium2))
|
2018-07-20 12:57:57 +00:00
|
|
|
|
data.AddLine(VerifyG1OTStadium(pkm, tr, s));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2019-12-09 01:39:19 +00:00
|
|
|
|
if (pkm.Species == (int)Species.Mew)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
var OTMatch = (tr == Legal.GetG1OT_GFMew((int)LanguageID.Japanese))
|
|
|
|
|
|| (tr == Legal.GetG1OT_GFMew((int)LanguageID.English));
|
|
|
|
|
if (!OTMatch || pkm.TID != 22796)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LG1OTEvent));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-27 02:34:27 +00:00
|
|
|
|
if (pkm.OT_Gender == 1 && ((pkm.Format == 2 && pkm.Met_Location == 0) || (pkm.Format > 2 && pkm.VC1)))
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LG1OTGender));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
private void VerifyG1OTWithinBounds(LegalityAnalysis data, string str)
|
|
|
|
|
{
|
2019-03-21 04:50:44 +00:00
|
|
|
|
if (StringConverter12.GetIsG1English(str))
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (str.Length > 7 && !(data.EncounterOriginal is EncounterTrade)) // OT already verified; GER shuckle has 8 chars
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LOTLong));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2019-03-21 04:50:44 +00:00
|
|
|
|
else if (StringConverter12.GetIsG1Japanese(str))
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (str.Length > 5)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LOTLong));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2019-03-21 04:50:44 +00:00
|
|
|
|
else if (data.pkm.Korean && StringConverter2KOR.GetIsG2Korean(str))
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (str.Length > 5)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LOTLong));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LG1CharOT));
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
|
|
|
|
private CheckResult VerifyG1OTStadium(PKM pkm, string tr, IVersion s)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
2020-02-07 05:25:13 +00:00
|
|
|
|
if (pkm.OT_Gender != 0)
|
|
|
|
|
return GetInvalid(LG1OTGender);
|
|
|
|
|
|
2020-02-04 04:10:07 +00:00
|
|
|
|
int tid = pkm.TID;
|
|
|
|
|
if (pkm.Japanese)
|
|
|
|
|
{
|
|
|
|
|
if (tid == Legal.GetGBStadiumOTID_JPN(s.Version) && Legal.Stadium1JP == tr)
|
|
|
|
|
return GetValid(LG1StadiumJapanese);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (s.Version == GameVersion.Stadium && tid == 2000)
|
|
|
|
|
{
|
|
|
|
|
if (tr == "STADIUM" || tr == "STADE" || tr == "STADIO" || tr == "ESTADIO")
|
|
|
|
|
return GetValid(LG1StadiumInternational);
|
|
|
|
|
}
|
|
|
|
|
else // Stadium2
|
|
|
|
|
{
|
|
|
|
|
if (tid == 2000 && tr == "Stadium")
|
|
|
|
|
return GetValid(LG1StadiumInternational);
|
|
|
|
|
|
|
|
|
|
if (tid == 2001 && (tr == "Stade" || tr == "Stadion" || tr == "Stadio" || tr == "Estadio"))
|
|
|
|
|
return GetValid(LG1StadiumInternational);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return GetInvalid(LG1Stadium);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2018-07-01 17:49:11 +00:00
|
|
|
|
|
2020-08-31 02:59:21 +00:00
|
|
|
|
private static bool IsOTNameSuspicious(string name)
|
2018-07-01 17:49:11 +00:00
|
|
|
|
{
|
2018-07-27 02:34:27 +00:00
|
|
|
|
return SuspiciousOTNames.Any(name.StartsWith);
|
2018-07-01 17:49:11 +00:00
|
|
|
|
}
|
2018-10-09 00:57:34 +00:00
|
|
|
|
|
2020-08-31 02:59:21 +00:00
|
|
|
|
public static bool IsOTIDSuspicious(int tid16, int sid16)
|
|
|
|
|
{
|
|
|
|
|
if (tid16 == 12345 && sid16 == 54321)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// 1234_123456 (SID7_TID7)
|
|
|
|
|
if (tid16 == 15040 && sid16 == 18831)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 00:57:34 +00:00
|
|
|
|
public static bool ContainsTooManyNumbers(string str, int originalGeneration)
|
|
|
|
|
{
|
|
|
|
|
if (originalGeneration <= 3)
|
|
|
|
|
return false; // no limit from these generations
|
|
|
|
|
int max = originalGeneration < 6 ? 4 : 5;
|
2018-10-10 02:28:18 +00:00
|
|
|
|
if (str.Length <= max)
|
2018-10-09 00:57:34 +00:00
|
|
|
|
return false;
|
|
|
|
|
int count = GetNumberCount(str);
|
|
|
|
|
return count > max;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int GetNumberCount(string str)
|
|
|
|
|
{
|
2019-10-08 01:40:09 +00:00
|
|
|
|
static bool IsNumber(char c)
|
2018-10-09 00:57:34 +00:00
|
|
|
|
{
|
|
|
|
|
if ('0' <= c)
|
|
|
|
|
return c <= '9';
|
|
|
|
|
return c <= '9' && '0' <= c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return str.Count(IsNumber);
|
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|