Split Trainer verifier into TrainerName and TrainerID

verify BDSP legality restrictions

Enforce nonzero TID/SID in Trainer Editor window (can use Block Data editor to set whatever without restriction, idc).

#3305
This commit is contained in:
Kurt 2021-11-25 19:15:42 -08:00
parent d9012b7d90
commit a761704a34
5 changed files with 84 additions and 45 deletions

View file

@ -399,6 +399,7 @@ namespace PKHeX.Core
public static string LOT_SID0 { get; set; } = "SID is zero."; public static string LOT_SID0 { get; set; } = "SID is zero.";
public static string LOT_SID0Invalid { get; set; } = "SID should be 0."; public static string LOT_SID0Invalid { get; set; } = "SID should be 0.";
public static string LOT_TID0 { get; set; } = "TID is zero."; public static string LOT_TID0 { get; set; } = "TID is zero.";
public static string LOT_IDInvalid { get; set; } = "TID and SID combination is not possible.";
public static string LPIDEncryptWurmple { get; set; } = "Wurmple evolution Encryption Constant mismatch."; public static string LPIDEncryptWurmple { get; set; } = "Wurmple evolution Encryption Constant mismatch.";
public static string LPIDEncryptZero { get; set; } = "Encryption Constant is not set."; public static string LPIDEncryptZero { get; set; } = "Encryption Constant is not set.";

View file

@ -274,6 +274,7 @@ namespace PKHeX.Core
Nickname.Verify(this); Nickname.Verify(this);
LanguageIndex.Verify(this); LanguageIndex.Verify(this);
Trainer.Verify(this); Trainer.Verify(this);
TrainerID.Verify(this);
IndividualValues.Verify(this); IndividualValues.Verify(this);
EffortValues.Verify(this); EffortValues.Verify(this);
Level.Verify(this); Level.Verify(this);

View file

@ -27,6 +27,7 @@
public static readonly ContestStatVerifier Contest = new(); public static readonly ContestStatVerifier Contest = new();
public static readonly TrainerNameVerifier Trainer = new(); public static readonly TrainerNameVerifier Trainer = new();
public static readonly TrainerIDVerifier TrainerID = new();
public static readonly LevelVerifier Level = new(); public static readonly LevelVerifier Level = new();
public static readonly MiscVerifier MiscValues = new(); public static readonly MiscVerifier MiscValues = new();
public static readonly TransferVerifier Transfer = new(); public static readonly TransferVerifier Transfer = new();

View file

@ -0,0 +1,69 @@
namespace PKHeX.Core
{
/// <summary>
/// Verifies the <see cref="PKM.OT_Name"/>.
/// </summary>
public sealed class TrainerIDVerifier : Verifier
{
protected override CheckIdentifier Identifier => CheckIdentifier.Trainer;
public override void Verify(LegalityAnalysis data)
{
var pkm = data.pkm;
if (!TrainerNameVerifier.IsPlayerOriginalTrainer(data.EncounterMatch))
return; // already verified
if (pkm.BDSP)
{
if (pkm.TID == 0 && pkm.SID == 0) // Game loops to ensure a nonzero full-ID
{
data.AddLine(GetInvalid(LegalityCheckStrings.LOT_IDInvalid));
return;
}
if (pkm.TID == 0xFFFF && pkm.SID == 0x7FFF) // int.MaxValue cannot be yielded by Unity's Random.Range[min, max)
{
data.AddLine(GetInvalid(LegalityCheckStrings.LOT_IDInvalid));
return;
}
}
else if (pkm.VC && pkm.SID != 0)
{
data.AddLine(GetInvalid(LegalityCheckStrings.LOT_SID0Invalid));
return;
}
if (pkm.TID == 0 && pkm.SID == 0)
{
data.AddLine(Get(LegalityCheckStrings.LOT_IDs0, Severity.Fishy));
}
else if (pkm.TID == pkm.SID)
{
data.AddLine(Get(LegalityCheckStrings.LOT_IDEqual, Severity.Fishy));
}
else if (pkm.TID == 0)
{
data.AddLine(Get(LegalityCheckStrings.LOT_TID0, Severity.Fishy));
}
else if (pkm.SID == 0)
{
data.AddLine(Get(LegalityCheckStrings.LOT_SID0, Severity.Fishy));
}
else if (IsOTIDSuspicious(pkm.TID, pkm.SID))
{
data.AddLine(Get(LegalityCheckStrings.LOTSuspicious, Severity.Fishy));
}
}
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;
}
}
}

View file

@ -19,44 +19,15 @@ namespace PKHeX.Core
public override void Verify(LegalityAnalysis data) public override void Verify(LegalityAnalysis data)
{ {
var pkm = data.pkm; var pkm = data.pkm;
switch (data.EncounterMatch) var enc = data.EncounterMatch;
{ if (!IsPlayerOriginalTrainer(enc))
case EncounterTrade: return; // already verified
case MysteryGift {IsEgg: false}:
case EncounterStatic5N:
return; // already verified
}
var ot = pkm.OT_Name; var ot = pkm.OT_Name;
if (ot.Length == 0) if (ot.Length == 0)
data.AddLine(GetInvalid(LOTShort)); data.AddLine(GetInvalid(LOTShort));
if (pkm.TID == 0 && pkm.SID == 0) if (IsOTNameSuspicious(ot))
{
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 (IsOTNameSuspicious(ot))
{
data.AddLine(Get(LOTSuspicious, Severity.Fishy));
}
else if (IsOTIDSuspicious(pkm.TID, pkm.SID))
{ {
data.AddLine(Get(LOTSuspicious, Severity.Fishy)); data.AddLine(Get(LOTSuspicious, Severity.Fishy));
} }
@ -82,6 +53,14 @@ namespace PKHeX.Core
} }
} }
internal static bool IsPlayerOriginalTrainer(IEncounterable enc) => enc switch
{
EncounterTrade { HasTrainerName: true } => true,
MysteryGift { IsEgg: false } => true,
EncounterStatic5N => true,
_ => false,
};
public static bool IsEdgeCaseLength(PKM pkm, IEncounterTemplate e, string ot) public static bool IsEdgeCaseLength(PKM pkm, IEncounterTemplate e, string ot)
{ {
if (e.EggEncounter) if (e.EggEncounter)
@ -160,18 +139,6 @@ namespace PKHeX.Core
return false; return false;
} }
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;
}
public static bool ContainsTooManyNumbers(string str, int originalGeneration) public static bool ContainsTooManyNumbers(string str, int originalGeneration)
{ {
if (originalGeneration <= 3) if (originalGeneration <= 3)