2018-06-24 05:00:01 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX.Core
|
|
|
|
|
{
|
2018-07-02 02:17:37 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Verifies the <see cref="PKM.Ball"/> value.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class BallVerifier : Verifier
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
protected override CheckIdentifier Identifier => CheckIdentifier.Ball;
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult NONE => GetInvalid(V125);
|
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
public override void Verify(LegalityAnalysis data)
|
|
|
|
|
{
|
2018-06-30 17:34:09 +00:00
|
|
|
|
if (data.pkm.Format <= 2)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
return; // no ball info saved
|
2018-06-30 17:34:09 +00:00
|
|
|
|
var result = VerifyBall(data);
|
|
|
|
|
data.AddLine(result);
|
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBall(LegalityAnalysis data)
|
|
|
|
|
{
|
2018-06-24 05:00:01 +00:00
|
|
|
|
var EncounterMatch = data.EncounterMatch;
|
|
|
|
|
var Info = data.Info;
|
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
// Fixed ball cases -- can be only one ball ever
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift g)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallMysteryGift(data, g);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (EncounterMatch is EncounterLink l)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, l.Ball);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (EncounterMatch is EncounterTrade t)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, t.Ball);
|
|
|
|
|
if (EncounterMatch is EncounterStatic s && s.Gift)
|
|
|
|
|
return VerifyBallEquals(data, s.Ball);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
// Capture / Inherit cases -- can be one of many balls
|
|
|
|
|
var pkm = data.pkm;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (pkm.Species == 292 && Info.Generation > 3) // Shedinja. For gen3, copy the ball from Nincada
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, 4); // Pokeball Only
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-07-27 02:34:27 +00:00
|
|
|
|
if (pkm.Ball == 0x14 && Legal.AlolanCaptureNoHeavyBall.Contains(EncounterMatch.Species) && !EncounterMatch.EggEncounter && pkm.SM)
|
|
|
|
|
return GetInvalid(V116); // Heavy Ball, can inherit if from egg (USUM fixed catch rate calc)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
if (EncounterMatch is EncounterStatic e)
|
|
|
|
|
return VerifyBallStatic(data, e);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot w)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallWild(data, w);
|
|
|
|
|
if (EncounterMatch is EncounterEgg)
|
|
|
|
|
return VerifyBallEgg(data);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, 4); // Pokeball
|
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallMysteryGift(LegalityAnalysis data, MysteryGift g)
|
|
|
|
|
{
|
|
|
|
|
if (g.Gen4 && g.Species == 490 && g.Ball == 0) // there is no ball data in Manaphy Mystery Gift from Gen4
|
|
|
|
|
return VerifyBallEquals(data, 4); // Pokeball
|
|
|
|
|
return VerifyBallEquals(data, g.Ball);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallStatic(LegalityAnalysis data, EncounterStatic s)
|
|
|
|
|
{
|
|
|
|
|
if (s.Location == 75 && s.Generation == 5) // Entree Forest (Dream World)
|
|
|
|
|
return VerifyBallEquals(data, Legal.DreamWorldBalls);
|
|
|
|
|
return VerifyBallEquals(data, Legal.GetWildBalls(data.pkm));
|
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallWild(LegalityAnalysis data, EncounterSlot w)
|
|
|
|
|
{
|
|
|
|
|
if (w.Location == 30016 && w.Generation == 7) // Poké Pelago
|
|
|
|
|
return VerifyBallEquals(data, 4); // Pokeball
|
|
|
|
|
|
|
|
|
|
var Info = data.Info;
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
if (3 <= Info.Generation && Info.Generation <= 4 && w.Type.IsSafariType())
|
|
|
|
|
return VerifyBallEquals(data, 5); // Safari Ball
|
|
|
|
|
if (Info.Generation == 4 && w.Type == SlotType.BugContest)
|
|
|
|
|
return VerifyBallEquals(data, 0x18); // Sport Ball
|
|
|
|
|
return VerifyBallEquals(data, Legal.GetWildBalls(data.pkm));
|
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallEgg(LegalityAnalysis data)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
|
|
|
|
if (data.Info.Generation < 6) // No inheriting Balls
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, 4); // Must be Pokéball -- no ball inheritance.
|
|
|
|
|
|
|
|
|
|
switch (pkm.Ball)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
2018-06-30 17:34:09 +00:00
|
|
|
|
case 0x04: return GetValid(V119); // Poké Ball
|
|
|
|
|
case 0x01: return GetInvalid(V117); // Master Ball
|
|
|
|
|
case 0x10: return GetInvalid(V120); // Cherish Ball
|
|
|
|
|
default: return VerifyBallInherited(data);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2018-06-30 17:34:09 +00:00
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallInherited(LegalityAnalysis data)
|
|
|
|
|
{
|
2018-06-24 05:00:01 +00:00
|
|
|
|
switch (data.Info.Generation)
|
|
|
|
|
{
|
2018-06-30 17:34:09 +00:00
|
|
|
|
case 6: return VerifyBallEggGen6(data); // Gen6 Inheritance Rules
|
|
|
|
|
case 7: return VerifyBallEggGen7(data); // Gen7 Inheritance Rules
|
|
|
|
|
default: return NONE;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-30 17:34:09 +00:00
|
|
|
|
|
|
|
|
|
private CheckResult VerifyBallEggGen6(LegalityAnalysis data)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
2018-07-01 17:49:11 +00:00
|
|
|
|
int species = data.EncounterMatch.Species;
|
|
|
|
|
if (pkm.Gender == 2 || Legal.BreedMaleOnly.Contains(species)) // Genderless
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, 4); // Must be Pokéball as ball can only pass via mother (not Ditto!)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
int ball = pkm.Ball;
|
|
|
|
|
|
|
|
|
|
if (ball >= 26)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V126);
|
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (ball == 0x05) // Safari Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Inherit_Safari.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
|
|
|
|
if (pkm.AbilityNumber == 4)
|
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (0x10 < ball && ball < 0x18) // Apricorn Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Inherit_Apricorn6.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (ball == 0x18) // Sport Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Inherit_Sport.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
|
|
|
|
if (pkm.AbilityNumber == 4)
|
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (ball == 0x19) // Dream Ball
|
|
|
|
|
{
|
2018-07-01 17:49:11 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4 && Legal.Ban_DreamHidden.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V122);
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (Legal.Inherit_Dream.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2018-06-30 17:34:09 +00:00
|
|
|
|
if (0x0D <= ball && ball <= 0x0F) // Dusk Heal Quick
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
2018-07-01 17:49:11 +00:00
|
|
|
|
if (!Legal.Ban_Gen4Ball_6.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked.
|
|
|
|
|
{
|
2018-07-01 17:49:11 +00:00
|
|
|
|
if (Legal.Ban_Gen3Ball.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
|
|
|
|
if (pkm.AbilityNumber == 4 && Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm))
|
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 17:49:11 +00:00
|
|
|
|
if (species > 650 && species != 700) // Sylveon
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
2018-07-01 17:49:11 +00:00
|
|
|
|
if (Legal.WildPokeballs6.Contains(pkm.Ball))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return NONE;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallEggGen7(LegalityAnalysis data)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
2018-07-01 17:49:11 +00:00
|
|
|
|
int species = data.EncounterMatch.Species;
|
|
|
|
|
if (722 <= species && species <= 730) // G7 Starters
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return VerifyBallEquals(data, 4);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
int ball = pkm.Ball;
|
2018-07-01 17:13:26 +00:00
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (ball == 0x05) // Safari Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species)))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4 && Legal.Ban_SafariBallHidden_7.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (0x10 < ball && ball < 0x18) // Apricorn Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Inherit_Apricorn7.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden7Apricorn.Contains(species | pkm.AltForm << 11)) // lineage is 3->2->origin
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (ball == 0x18) // Sport Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Inherit_Sport.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V121);
|
2018-07-09 13:28:23 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4 && (species == 313 || species == 314)) // Volbeat/Illumise
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V122);
|
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (ball == 0x19) // Dream Ball
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (Legal.Inherit_Dream.Contains(species) || Legal.Inherit_DreamMale.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (0x0D <= ball && ball <= 0x0F) // Dusk Heal Quick
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Ban_Gen4Ball_7.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked.
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (!Legal.Ban_Gen3Ball_7.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
|
|
|
|
return GetInvalid(V121);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ball == 26)
|
|
|
|
|
{
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (species == 669 && pkm.AltForm == 3 && pkm.AbilityNumber == 4)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V122); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
2018-08-26 16:43:11 +00:00
|
|
|
|
if ((species > 731 && species <= 785) || (Legal.AlolanCaptureOffspring.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species)))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
2018-07-01 17:13:26 +00:00
|
|
|
|
if (Legal.PastGenAlolanScans.Contains(species))
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetValid(V123);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
// next statement catches all new alolans
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 17:49:11 +00:00
|
|
|
|
if (species > 721)
|
|
|
|
|
return VerifyBallEquals(data, Legal.WildPokeballs7);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
if (ball >= 27)
|
2018-06-30 17:34:09 +00:00
|
|
|
|
return GetInvalid(V126);
|
|
|
|
|
|
|
|
|
|
return NONE;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallEquals(LegalityAnalysis data, int ball) => GetResult(ball == data.pkm.Ball);
|
2018-07-01 17:49:11 +00:00
|
|
|
|
private CheckResult VerifyBallEquals(LegalityAnalysis data, HashSet<int> balls) => GetResult(balls.Contains(data.pkm.Ball));
|
2018-06-30 17:34:09 +00:00
|
|
|
|
private CheckResult VerifyBallEquals(LegalityAnalysis data, ICollection<int> balls) => GetResult(balls.Contains(data.pkm.Ball));
|
2018-07-27 02:34:27 +00:00
|
|
|
|
private CheckResult GetResult(bool valid) => valid ? GetValid(V119) : GetInvalid(V118);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|