mirror of
https://github.com/kwsch/PKHeX
synced 2024-12-18 00:13:10 +00:00
e29cf2a903
Checks.cs initially started out small, but over the years it has grown to handle multiple types of checks. With all these checks next to eachother, it's hard to see the overall groups. Splitting them up (potentially further?) allows for more focused maintenance & understanding. Not sure if I'm happy with the overall bandaids used (checks no longer done within LegalityAnalysis so variable repointing is excessively used), but I'm happier the way it is now compared to the huge Checks.cs
233 lines
10 KiB
C#
233 lines
10 KiB
C#
using System.Linq;
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
public class MiscVerifier : Verifier
|
|
{
|
|
protected override CheckIdentifier Identifier => CheckIdentifier.Misc;
|
|
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(V320, CheckIdentifier.Egg));
|
|
if (pkm is PK4 pk4)
|
|
{
|
|
if (pk4.ShinyLeaf != 0)
|
|
data.AddLine(GetInvalid(V414, CheckIdentifier.Egg));
|
|
if (pk4.PokéathlonStat != 0)
|
|
data.AddLine(GetInvalid(V415, CheckIdentifier.Egg));
|
|
}
|
|
if (pkm is PK3)
|
|
{
|
|
if (pkm.Language != 1) // All Eggs are Japanese and flagged specially for localized string
|
|
data.AddLine(GetInvalid(string.Format(V5, LanguageID.Japanese, (LanguageID)pkm.Language), CheckIdentifier.Egg));
|
|
}
|
|
}
|
|
|
|
|
|
VerifyMiscFatefulEncounter(data);
|
|
}
|
|
|
|
public void VerifyMiscG1(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (pkm.IsEgg)
|
|
{
|
|
VerifyMiscEggCommon(data);
|
|
if (pkm.PKRS_Cured || pkm.PKRS_Infected)
|
|
data.AddLine(GetInvalid(V368, CheckIdentifier.Egg));
|
|
}
|
|
|
|
if (!(pkm is PK1 pk1))
|
|
return;
|
|
|
|
VerifyMiscG1Types(data, pk1);
|
|
VerifyMiscG1CatchRate(data, pk1);
|
|
}
|
|
private void VerifyMiscG1Types(LegalityAnalysis data, PK1 pk1)
|
|
{
|
|
var Type_A = pk1.Type_A;
|
|
var Type_B = pk1.Type_B;
|
|
if (pk1.Species == 137)
|
|
{
|
|
// Porygon can have any type combination of any generation 1 species because of the move Conversion,
|
|
// that change Porygon type to match the oponent types
|
|
var Type_A_Match = Legal.Types_Gen1.Any(t => t == Type_A);
|
|
var Type_B_Match = Legal.Types_Gen1.Any(t => t == Type_B);
|
|
if (!Type_A_Match)
|
|
data.AddLine(GetInvalid(V386));
|
|
if (!Type_B_Match)
|
|
data.AddLine(GetInvalid(V387));
|
|
if (Type_A_Match && Type_B_Match)
|
|
{
|
|
var TypesAB_Match = PersonalTable.RB.IsValidTypeCombination(Type_A, Type_B);
|
|
if (TypesAB_Match)
|
|
data.AddLine(GetValid(V391));
|
|
else
|
|
data.AddLine(GetInvalid(V388));
|
|
}
|
|
}
|
|
else // Types must match species types
|
|
{
|
|
var Type_A_Match = Type_A == PersonalTable.RB[pk1.Species].Type1;
|
|
var Type_B_Match = Type_B == PersonalTable.RB[pk1.Species].Type2;
|
|
|
|
var first = Type_A_Match ? GetValid(V392) : GetInvalid(V389);
|
|
var second = Type_B_Match ? GetValid(V393) : GetInvalid(V390);
|
|
data.AddLine(first);
|
|
data.AddLine(second);
|
|
}
|
|
}
|
|
private void VerifyMiscG1CatchRate(LegalityAnalysis data, PK1 pk1)
|
|
{
|
|
var EncounterMatch = data.EncounterMatch;
|
|
var catch_rate = pk1.Catch_Rate;
|
|
switch (pk1.TradebackStatus)
|
|
{
|
|
case TradebackType.Any:
|
|
case TradebackType.WasTradeback:
|
|
if (catch_rate == 0 || Legal.HeldItems_GSC.Any(h => h == catch_rate))
|
|
data.AddLine(GetValid(V394));
|
|
else if (pk1.TradebackStatus == TradebackType.WasTradeback)
|
|
data.AddLine(GetInvalid(V395));
|
|
else
|
|
goto case TradebackType.Gen1_NotTradeback;
|
|
break;
|
|
case TradebackType.Gen1_NotTradeback:
|
|
if ((EncounterMatch as EncounterStatic)?.Version == GameVersion.Stadium || EncounterMatch is EncounterTradeCatchRate)
|
|
// Encounters detected by the catch rate, cant be invalid if match this encounters
|
|
data.AddLine(GetValid(V398));
|
|
else if (pk1.Species == 149 && catch_rate == PersonalTable.Y[149].CatchRate || Legal.Species_NotAvailable_CatchRate.Contains(pk1.Species) && catch_rate == PersonalTable.RB[pk1.Species].CatchRate)
|
|
data.AddLine(GetInvalid(V396));
|
|
else if (!data.Info.EvoChainsAllGens[1].Any(e => catch_rate == PersonalTable.RB[e.Species].CatchRate || catch_rate == PersonalTable.Y[e.Species].CatchRate))
|
|
data.AddLine(GetInvalid(pk1.Gen1_NotTradeback ? V397 : V399));
|
|
else
|
|
data.AddLine(GetValid(V398));
|
|
break;
|
|
}
|
|
}
|
|
private void VerifyMiscFatefulEncounter(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
var EncounterMatch = data.EncounterMatch;
|
|
switch (EncounterMatch)
|
|
{
|
|
case WC3 w when w.Fateful:
|
|
if (w.IsEgg)
|
|
{
|
|
// Eggs hatched in RS clear the obedience flag!
|
|
if (pkm.Format != 3)
|
|
return; // possible hatched in either game, don't bother checking
|
|
if (pkm.Met_Location <= 087) // hatched in RS
|
|
break; // ensure fateful is not active
|
|
// else, ensure fateful is active (via below)
|
|
}
|
|
VerifyFatefulIngameActive(data);
|
|
VerifyWC3Shiny(data, w);
|
|
return;
|
|
case WC3 w:
|
|
if (w.Version == GameVersion.XD)
|
|
return; // Can have either state
|
|
VerifyWC3Shiny(data, w);
|
|
break;
|
|
case MysteryGift g when g.Format != 3: // WC3
|
|
VerifyFatefulMysteryGift(data, g);
|
|
return;
|
|
case EncounterStatic s when s.Fateful: // ingame fateful
|
|
case EncounterSlot _ when pkm.Version == 15: // ingame pokespot
|
|
case EncounterTrade t when t.Fateful:
|
|
VerifyFatefulIngameActive(data);
|
|
return;
|
|
}
|
|
if (pkm.FatefulEncounter)
|
|
data.AddLine(GetInvalid(V325, CheckIdentifier.Fateful));
|
|
}
|
|
private void VerifyMiscEggCommon(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (pkm.Move1_PPUps > 0 || pkm.Move2_PPUps > 0 || pkm.Move3_PPUps > 0 || pkm.Move4_PPUps > 0)
|
|
data.AddLine(GetInvalid(V319, CheckIdentifier.Egg));
|
|
if (pkm.Move1_PP != pkm.GetMovePP(pkm.Move1, 0) || pkm.Move2_PP != pkm.GetMovePP(pkm.Move2, 0)
|
|
|| pkm.Move3_PP != pkm.GetMovePP(pkm.Move3, 0) || pkm.Move4_PP != pkm.GetMovePP(pkm.Move4, 0))
|
|
data.AddLine(GetInvalid(V420, CheckIdentifier.Egg));
|
|
|
|
var EncounterMatch = data.EncounterMatch;
|
|
var HatchCycles = (EncounterMatch as EncounterStatic)?.EggCycles;
|
|
if (HatchCycles == 0 || HatchCycles == null)
|
|
HatchCycles = pkm.PersonalInfo.HatchCycles;
|
|
if (pkm.CurrentFriendship > HatchCycles)
|
|
data.AddLine(GetInvalid(V374, CheckIdentifier.Egg));
|
|
|
|
if (pkm.Format >= 6 && EncounterMatch is EncounterEgg && !pkm.Moves.SequenceEqual(pkm.RelearnMoves))
|
|
{
|
|
var moves = string.Join(", ", LegalityAnalysis.GetMoveNames(pkm.Moves));
|
|
var msg = string.Format(V343, moves);
|
|
data.AddLine(GetInvalid(msg, CheckIdentifier.Egg));
|
|
}
|
|
}
|
|
private void VerifyFatefulMysteryGift(LegalityAnalysis data, MysteryGift g)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (g is PGF p && p.IsShiny)
|
|
{
|
|
var Info = data.Info;
|
|
Info.PIDIV = MethodFinder.Analyze(pkm);
|
|
if (Info.PIDIV.Type != PIDType.G5MGShiny && pkm.Egg_Location != 30003)
|
|
data.AddLine(GetInvalid(V411, CheckIdentifier.PID));
|
|
}
|
|
|
|
if (pkm.FatefulEncounter)
|
|
data.AddLine(GetValid(V321, CheckIdentifier.Fateful));
|
|
else
|
|
data.AddLine(GetInvalid(V322, CheckIdentifier.Fateful));
|
|
}
|
|
private void VerifyWC3Shiny(LegalityAnalysis data, WC3 g3)
|
|
{
|
|
// check for shiny locked gifts
|
|
if (!g3.Shiny.IsValid(data.pkm))
|
|
data.AddLine(GetInvalid(V409, CheckIdentifier.Fateful));
|
|
}
|
|
private void VerifyFatefulIngameActive(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (pkm.Version == 15 && pkm is XK3 xk3 && data.Info.WasXD)
|
|
{
|
|
// can't have fateful until traded away, which clears ShadowID
|
|
if (xk3.FatefulEncounter && xk3.ShadowID != 0 && data.EncounterMatch is EncounterStaticShadow)
|
|
data.AddLine(GetInvalid(V325, CheckIdentifier.Fateful));
|
|
|
|
return; // fateful is set when transferred away
|
|
}
|
|
|
|
if (pkm.FatefulEncounter)
|
|
data.AddLine(GetValid(V323, CheckIdentifier.Fateful));
|
|
else
|
|
data.AddLine(GetInvalid(V324, CheckIdentifier.Fateful));
|
|
}
|
|
|
|
public void VerifyVersionEvolution(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (pkm.Format < 7 || data.EncounterMatch.Species == pkm.Species)
|
|
return;
|
|
|
|
// No point using the evolution tree. Just handle certain species.
|
|
switch (pkm.Species)
|
|
{
|
|
case 745 when (pkm.AltForm == 0 && Moon()) || (pkm.AltForm == 1 && Sun()): // Lycanroc
|
|
case 791 when Moon(): // Solgaleo
|
|
case 792 when Sun(): // Lunala
|
|
bool Sun() => pkm.Version == (int)GameVersion.SN || pkm.Version == (int)GameVersion.US;
|
|
bool Moon() => pkm.Version == (int)GameVersion.MN || pkm.Version == (int)GameVersion.UM;
|
|
if (pkm.IsUntraded)
|
|
data.AddLine(GetInvalid(V328, CheckIdentifier.Evolution));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|