PKHeX/PKHeX.Core/Legality/Verifiers/BallVerifier.cs
Kurt e29cf2a903 Rework secondary check flow
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
2018-06-23 22:00:01 -07:00

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));
}
}
}