mirror of
https://github.com/kwsch/PKHeX
synced 2025-03-07 08:47:21 +00:00
234 lines
10 KiB
C#
234 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;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|