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
330 lines
12 KiB
C#
330 lines
12 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
public class BallVerifier : Verifier
|
|
{
|
|
protected override CheckIdentifier Identifier => CheckIdentifier.Ball;
|
|
public override void Verify(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (pkm.Format < 3)
|
|
return; // no ball info saved
|
|
|
|
var EncounterMatch = data.EncounterMatch;
|
|
var Info = data.Info;
|
|
|
|
if (EncounterMatch is MysteryGift g)
|
|
{
|
|
if (pkm.Species == 490 && g.Ball == 0)
|
|
// there is no ball data in Manaphy Mystery Gift
|
|
VerifyBallEquals(data, 4); // Pokeball
|
|
else
|
|
VerifyBallEquals(data, g.Ball);
|
|
return;
|
|
}
|
|
if (EncounterMatch is EncounterLink l)
|
|
{
|
|
VerifyBallEquals(data, l.Ball);
|
|
return;
|
|
}
|
|
if (EncounterMatch is EncounterTrade t)
|
|
{
|
|
VerifyBallEquals(data, t.Ball); // Pokeball
|
|
return;
|
|
}
|
|
|
|
if (pkm.Species == 292 && Info.Generation > 3) // Shedinja. For gen3, copy the ball from Nincada
|
|
{
|
|
VerifyBallEquals(data, 4); // Pokeball Only
|
|
return;
|
|
}
|
|
|
|
if (pkm.Ball == 0x14 && !Info.EncounterMatch.EggEncounter && pkm.SM) // Heavy Ball
|
|
{
|
|
var lineage = EvolutionChain.GetLineage(pkm);
|
|
if (lineage.Any(e => Legal.AlolanCaptureNoHeavyBall.Contains(e)))
|
|
{
|
|
data.AddLine(GetInvalid(V116));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (EncounterMatch is EncounterStatic s)
|
|
{
|
|
if (s.Gift)
|
|
VerifyBallEquals(data, s.Ball);
|
|
else if (s.Location == 75 && s.Generation == 5) // Entree Forest (Dream World)
|
|
VerifyBallEquals(data, Legal.DreamWorldBalls);
|
|
else
|
|
VerifyBallEquals(data, Legal.GetWildBalls(pkm));
|
|
return;
|
|
}
|
|
if (EncounterMatch is EncounterSlot w)
|
|
{
|
|
if (w.Location == 30016 && w.Generation == 7) // Poké Pelago
|
|
VerifyBallEquals(data, 4); // Pokeball
|
|
// For gen3/4 Safari Zones and BCC getValidWildEncounters already filter to not return
|
|
// mixed possible encounters between safari, BCC and other encounters
|
|
// That means is the first encounter is not safari then there is no safari encounter in the array
|
|
else if (3 <= Info.Generation && Info.Generation <= 4 && w.Type.IsSafariType())
|
|
VerifyBallEquals(data, 5); // Safari Ball
|
|
else if (Info.Generation == 4 && w.Type == SlotType.BugContest)
|
|
VerifyBallEquals(data, 0x18); // Sport Ball
|
|
else
|
|
VerifyBallEquals(data, Legal.GetWildBalls(pkm));
|
|
return;
|
|
}
|
|
|
|
if (pkm.WasEgg)
|
|
{
|
|
VerifyBallEgg(data);
|
|
return;
|
|
}
|
|
|
|
VerifyBallEquals(data, 4); // Pokeball
|
|
}
|
|
private void VerifyBallEgg(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (data.Info.Generation < 6) // No inheriting Balls
|
|
{
|
|
VerifyBallEquals(data, 4); // Must be Pokéball -- no ball inheritance.
|
|
return;
|
|
}
|
|
|
|
if (pkm.Ball == 0x01) // Master Ball
|
|
{ data.AddLine(GetInvalid(V117)); return; }
|
|
if (pkm.Ball == 0x10) // Cherish Ball
|
|
{ data.AddLine(GetInvalid(V120)); return; }
|
|
if (pkm.Ball == 0x04) // Poké Ball
|
|
{ data.AddLine(GetValid(V119)); return; }
|
|
|
|
switch (data.Info.Generation)
|
|
{
|
|
case 6: // Gen6 Inheritance Rules
|
|
VerifyBallEggGen6(data);
|
|
return;
|
|
case 7: // Gen7 Inheritance Rules
|
|
VerifyBallEggGen7(data);
|
|
return;
|
|
}
|
|
}
|
|
private void VerifyBallEggGen6(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
if (pkm.Gender == 2) // Genderless
|
|
{
|
|
VerifyBallEquals(data, 4); // Must be Pokéball as ball can only pass via mother (not Ditto!)
|
|
return;
|
|
}
|
|
if (Legal.BreedMaleOnly.Contains(pkm.Species))
|
|
{
|
|
VerifyBallEquals(data, 4); // Must be Pokéball as ball can only pass via mother (not Ditto!)
|
|
return;
|
|
}
|
|
|
|
int ball = pkm.Ball;
|
|
|
|
if (ball >= 26)
|
|
{
|
|
data.AddLine(GetInvalid(V126));
|
|
return;
|
|
}
|
|
if (ball == 0x05) // Safari Ball
|
|
{
|
|
if (EvolutionChain.GetLineage(pkm).All(e => !Legal.Inherit_Safari.Contains(e)))
|
|
data.AddLine(GetInvalid(V121));
|
|
else if (pkm.AbilityNumber == 4)
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
if (0x10 < ball && ball < 0x18) // Apricorn Ball
|
|
{
|
|
if (EvolutionChain.GetLineage(pkm).All(e => !Legal.Inherit_Apricorn6.Contains(e)))
|
|
data.AddLine(GetInvalid(V121));
|
|
if (pkm.AbilityNumber == 4)
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
if (ball == 0x18) // Sport Ball
|
|
{
|
|
if (EvolutionChain.GetLineage(pkm).All(e => !Legal.Inherit_Sport.Contains(e)))
|
|
data.AddLine(GetInvalid(V121));
|
|
else if (pkm.AbilityNumber == 4)
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
if (ball == 0x19) // Dream Ball
|
|
{
|
|
if (EvolutionChain.GetLineage(pkm).Any(e => Legal.Inherit_Dream.Contains(e)))
|
|
data.AddLine(GetValid(V123));
|
|
else
|
|
data.AddLine(GetInvalid(V121));
|
|
|
|
if (pkm.AbilityNumber == 4 && Legal.Ban_DreamHidden.Contains(pkm.Species))
|
|
data.AddLine(GetInvalid(V122));
|
|
|
|
return;
|
|
}
|
|
if (0x0D <= ball && ball <= 0x0F)
|
|
{
|
|
if (!Legal.Ban_Gen4Ball_6.Contains(pkm.Species))
|
|
data.AddLine(GetValid(V123));
|
|
else
|
|
data.AddLine(GetInvalid(V121));
|
|
|
|
return;
|
|
}
|
|
if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked.
|
|
{
|
|
if (Legal.Ban_Gen3Ball.Contains(pkm.Species))
|
|
data.AddLine(GetInvalid(V121));
|
|
else if (pkm.AbilityNumber == 4 && Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm))
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
|
|
if (pkm.Species > 650 && pkm.Species != 700) // Sylveon
|
|
{
|
|
if (Legal.GetWildBalls(pkm).Contains(pkm.Ball))
|
|
data.AddLine(GetValid(V123));
|
|
else
|
|
data.AddLine(GetInvalid(V121));
|
|
return;
|
|
}
|
|
|
|
data.AddLine(GetInvalid(V125));
|
|
}
|
|
private void VerifyBallEggGen7(LegalityAnalysis data)
|
|
{
|
|
var pkm = data.pkm;
|
|
var Lineage = EvolutionChain.GetLineage(pkm).ToArray();
|
|
if (722 <= pkm.Species && pkm.Species <= 730) // G7 Starters
|
|
{
|
|
VerifyBallEquals(data, 4);
|
|
return;
|
|
}
|
|
|
|
int ball = pkm.Ball;
|
|
if (ball == 0x05) // Safari Ball
|
|
{
|
|
if (!Lineage.Any(e => Legal.Inherit_Safari.Contains(e) || Legal.Inherit_SafariMale.Contains(e)))
|
|
data.AddLine(GetInvalid(V121));
|
|
else if (pkm.AbilityNumber == 4 && Lineage.Any(e => Legal.Ban_SafariBallHidden_7.Contains(e)))
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
if (0x10 < ball && ball < 0x18) // Apricorn Ball
|
|
{
|
|
if (!Lineage.Any(e => Legal.Inherit_Apricorn7.Contains(e)))
|
|
data.AddLine(GetInvalid(V121));
|
|
else if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden7Apricorn.Contains(Lineage.Last() | pkm.AltForm << 11)) // lineage is 3->2->origin
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
if (ball == 0x18) // Sport Ball
|
|
{
|
|
if (!Lineage.Any(e => Legal.Inherit_Sport.Contains(e)))
|
|
data.AddLine(GetInvalid(V121));
|
|
else if (pkm.AbilityNumber == 4 && (Lineage.Contains(313) || Lineage.Contains(314))) // Volbeat/Illumise
|
|
data.AddLine(GetInvalid(V122));
|
|
else
|
|
data.AddLine(GetValid(V123));
|
|
|
|
return;
|
|
}
|
|
if (ball == 0x19) // Dream Ball
|
|
{
|
|
if (Lineage.Any(e => Legal.Inherit_Dream.Contains(e) || Legal.Inherit_DreamMale.Contains(e)))
|
|
data.AddLine(GetValid(V123));
|
|
else
|
|
data.AddLine(GetInvalid(V121));
|
|
|
|
return;
|
|
}
|
|
if (0x0D <= ball && ball <= 0x0F) // Dusk Heal Quick
|
|
{
|
|
if (!Legal.Ban_Gen4Ball_7.Contains(pkm.Species))
|
|
data.AddLine(GetValid(V123));
|
|
else
|
|
data.AddLine(GetInvalid(V121));
|
|
|
|
return;
|
|
}
|
|
if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked.
|
|
{
|
|
if (!Legal.Ban_Gen3Ball_7.Contains(pkm.Species))
|
|
data.AddLine(GetValid(V123));
|
|
else
|
|
data.AddLine(GetInvalid(V121));
|
|
|
|
return;
|
|
}
|
|
|
|
if (ball == 26)
|
|
{
|
|
if (Lineage[0] == 669 && pkm.AltForm == 3 && pkm.AbilityNumber == 4)
|
|
{
|
|
// Can't obtain Flabébé-Blue with Hidden Ability in wild
|
|
data.AddLine(GetInvalid(V122));
|
|
return;
|
|
}
|
|
if ((pkm.Species > 731 && pkm.Species <= 785) || Lineage.Any(e => Legal.PastGenAlolanNatives.Contains(e) && !Legal.PastGenAlolanNativesUncapturable.Contains(e)))
|
|
{
|
|
data.AddLine(GetValid(V123));
|
|
return;
|
|
}
|
|
if (Lineage.Any(e => Legal.PastGenAlolanScans.Contains(e)))
|
|
{
|
|
data.AddLine(GetValid(V123));
|
|
return;
|
|
}
|
|
// next statement catches all new alolans
|
|
}
|
|
|
|
if (pkm.Species > 721)
|
|
{
|
|
VerifyBallEquals(data, Legal.GetWildBalls(pkm));
|
|
return;
|
|
}
|
|
|
|
if (ball >= 27)
|
|
{
|
|
data.AddLine(GetInvalid(V126));
|
|
return;
|
|
}
|
|
data.AddLine(GetInvalid(V125));
|
|
}
|
|
|
|
private void VerifyBallEquals(LegalityAnalysis data, int ball) => AddBallLine(data, ball == data.pkm.Ball);
|
|
private void VerifyBallEquals(LegalityAnalysis data, ICollection<int> balls) => AddBallLine(data, balls.Contains(data.pkm.Ball));
|
|
private void AddBallLine(LegalityAnalysis data, bool valid)
|
|
{
|
|
if (valid)
|
|
data.AddLine(GetValid(V119));
|
|
else
|
|
data.AddLine(GetInvalid(V118));
|
|
}
|
|
}
|
|
}
|