PKHeX/PKHeX.Core/Legality/Verifiers/FormVerifier.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

259 lines
10 KiB
C#

using System;
using System.Linq;
using static PKHeX.Core.LegalityCheckStrings;
namespace PKHeX.Core
{
public class FormVerifier : Verifier
{
protected override CheckIdentifier Identifier => CheckIdentifier.Form;
public override void Verify(LegalityAnalysis data)
{
var pkm = data.pkm;
if (pkm.Format < 4)
return; // no forms exist
var PersonalInfo = data.PersonalInfo;
var EncounterMatch = data.EncounterMatch;
var Info = data.Info;
int count = PersonalInfo.FormeCount;
if (count <= 1 && pkm.AltForm == 0)
return; // no forms to check
if (!PersonalInfo.IsFormeWithinRange(pkm.AltForm) && !FormConverter.IsValidOutOfBoundsForme(pkm.Species, pkm.AltForm, Info.Generation))
{
data.AddLine(GetInvalid(string.Format(V304, count - 1, pkm.AltForm)));
return;
}
if (EncounterMatch is EncounterSlot w && w.Type == SlotType.FriendSafari)
VerifyFormFriendSafari(data);
else if (EncounterMatch is EncounterEgg)
{
if (FormConverter.IsTotemForm(pkm.Species, pkm.AltForm))
{
data.AddLine(GetInvalid(V317));
return;
}
}
switch (pkm.Species)
{
case 25 when Info.Generation == 6: // Pikachu Cosplay
bool isStatic = EncounterMatch is EncounterStatic;
if (isStatic != (pkm.AltForm != 0))
{
string msg = isStatic ? V305 : V306;
data.AddLine(GetInvalid(msg));
return;
}
break;
case 25 when Info.Generation == 7: // Pikachu Cap
bool IsValidPikachuCap()
{
switch (EncounterMatch)
{
default: return pkm.AltForm == 0;
case WC7 wc7: return wc7.Form == pkm.AltForm;
case EncounterStatic s: return s.Form == pkm.AltForm;
}
}
if (!IsValidPikachuCap())
{
bool gift = EncounterMatch is WC7 g && g.Form != pkm.AltForm;
var msg = gift ? V307 : V317;
data.AddLine(GetInvalid(msg));
return;
}
break;
case 201 when Info.Generation == 2 && pkm.AltForm >= 26:
data.AddLine(GetInvalid(string.Format(V304, "Z", pkm.AltForm == 26 ? "!" : "?")));
break;
case 487: // Giratina
if (pkm.AltForm == 1 ^ pkm.HeldItem == 112) // Origin form only with Griseous Orb
{
data.AddLine(GetInvalid(V308));
return;
}
break;
case 493: // Arceus
{
int item = pkm.HeldItem;
int form = 0;
if (298 <= item && item <= 313 || item == 644)
form = Array.IndexOf(Legal.Arceus_Plate, item) + 1;
else if (777 <= item && item <= 793)
form = Array.IndexOf(Legal.Arceus_ZCrystal, item) + 1;
if (pkm.Format == 4 && form >= 9)
form++; // ??? type Form shifts everything by 1
if (form != pkm.AltForm)
data.AddLine(GetInvalid(V308));
else if (form != 0)
data.AddLine(GetValid(V309));
}
break;
case 647: // Keldeo
{
if (pkm.Gen5) // can mismatch in gen5 via BW tutor and transfer up
break;
int index = Array.IndexOf(pkm.Moves, 548); // Secret Sword
bool noSword = index < 0;
if (pkm.AltForm == 0 ^ noSword) // mismatch
Info.Moves[noSword ? 0 : index] = new CheckMoveResult(Info.Moves[noSword ? 0 : index], Severity.Invalid, V169, CheckIdentifier.Move);
break;
}
case 649: // Genesect
{
int item = pkm.HeldItem;
int form = 0;
if (116 <= item && item <= 119)
form = item - 115;
if (form != pkm.AltForm)
data.AddLine(GetInvalid(V308));
else
data.AddLine(GetValid(V309));
}
break;
case 658: // Greninja
if (pkm.AltForm > 1) // Ash Battle Bond active
{
data.AddLine(GetInvalid(V310));
return;
}
if (pkm.AltForm != 0 && !(EncounterMatch is MysteryGift)) // Formes are not breedable, MysteryGift already checked
{
data.AddLine(GetInvalid(string.Format(V304, 0, pkm.AltForm)));
return;
}
break;
case 664: // Scatterbug
case 665: // Spewpa
if (pkm.AltForm > 17) // Fancy & Pokéball
{
data.AddLine(GetInvalid(V311));
return;
}
if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region))
data.AddLine(Get(V312, Severity.Fishy));
break;
case 666: // Vivillon
if (pkm.AltForm > 17) // Fancy & Pokéball
{
if (!(EncounterMatch is MysteryGift))
data.AddLine(GetInvalid(V312));
else
data.AddLine(GetValid(V313));
return;
}
if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region))
data.AddLine(Get(V312, Severity.Fishy));
break;
case 670: // Floette
if (pkm.AltForm == 5) // Eternal Flower -- Never Released
{
if (!(EncounterMatch is MysteryGift))
data.AddLine(GetInvalid(V314));
else
data.AddLine(GetValid(V315));
return;
}
break;
case 678: // Meowstic
if (pkm.AltForm != pkm.Gender)
data.AddLine(GetInvalid(V203));
break;
case 773: // Silvally
{
int item = pkm.HeldItem;
int form = 0;
if ((904 <= item && item <= 920) || item == 644)
form = item - 903;
if (form != pkm.AltForm)
data.AddLine(GetInvalid(V308));
else if (form != 0)
data.AddLine(GetValid(V309));
break;
}
case 744 when Info.EncounterMatch.EggEncounter && pkm.AltForm == 1 && pkm.SM:
case 745 when Info.EncounterMatch.EggEncounter && pkm.AltForm == 2 && pkm.SM:
data.AddLine(GetInvalid(V317));
return;
// Impossible Egg forms
case 479 when pkm.IsEgg: // Rotom
case 676 when pkm.IsEgg: // Furfrou
if (pkm.AltForm != 0) // has form
{
data.AddLine(GetInvalid(V50));
return;
}
break;
// Party Only Forms
case 492: // Shaymin
case 676: // Furfrou
case 720: // Hoopa
if (pkm.AltForm != 0 && pkm.Box > -1 && pkm.Format <= 6) // has form but stored in box
{
data.AddLine(GetInvalid(V316));
return;
}
break;
// Battle only Forms with other legal forms allowed
case 718 when pkm.AltForm >= 4: // Zygarde Complete
case 774 when pkm.AltForm < 7: // Minior Shield
case 800 when pkm.AltForm == 3: // Ultra Necrozma
data.AddLine(GetInvalid(V310));
return;
case 800 when pkm.AltForm < 3: // Necrozma Fused forms & default
case 778 when pkm.AltForm == 2: // Totem disguise Mimikyu
data.AddLine(GetValid(V318));
return;
}
if (pkm.Format >= 7 && Info.Generation < 7 && pkm.AltForm != 0)
{
if (pkm.Species == 25 || Legal.AlolanOriginForms.Contains(pkm.Species)
|| Legal.AlolanVariantEvolutions12.Contains(data.EncounterOriginal.Species))
{ data.AddLine(GetInvalid(V317)); return; }
}
if (pkm.AltForm > 0 && new[] { Legal.BattleForms, Legal.BattleMegas, Legal.BattlePrimals }.Any(arr => arr.Contains(pkm.Species)))
{ data.AddLine(GetInvalid(V310)); return; }
data.AddLine(GetValid(V318));
}
private void VerifyFormFriendSafari(LegalityAnalysis data)
{
var pkm = data.pkm;
switch (pkm.Species)
{
case 670: // Floette
case 671: // Florges
if (!new[] { 0, 1, 3 }.Contains(pkm.AltForm)) // 0/1/3 - RBY
data.AddLine(GetInvalid(V64));
break;
case 710 when pkm.AltForm != 0: // Pumpkaboo
case 711 when pkm.AltForm != 0: // Goregeist Average
data.AddLine(GetInvalid(V6));
break;
case 423 when pkm.AltForm != 0: // Gastrodon West
data.AddLine(GetInvalid(V64));
break;
case 586 when pkm.AltForm != 0: // Sawsbuck
data.AddLine(GetInvalid(V65));
break;
}
}
}
}