2018-06-24 05:00:01 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX.Core
|
|
|
|
|
{
|
2018-07-02 02:17:37 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Verifies the transfer data for a <see cref="PKM"/> that has been irreversably transferred forward.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class TransferVerifier : Verifier
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
protected override CheckIdentifier Identifier => CheckIdentifier.Encounter;
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
public override void Verify(LegalityAnalysis data)
|
|
|
|
|
{
|
2019-10-26 19:33:58 +00:00
|
|
|
|
throw new Exception("Don't call via this.");
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-04 03:13:30 +00:00
|
|
|
|
public void VerifyTransferLegalityG12(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
VerifyTransferVCNatureEXP(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void VerifyTransferVCNatureEXP(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
|
|
|
|
var met = pkm.Met_Level;
|
|
|
|
|
|
|
|
|
|
if (met == 100) // check for precise match, can't receive EXP after transfer.
|
|
|
|
|
{
|
|
|
|
|
var nature = Experience.GetNatureVC(pkm.EXP);
|
|
|
|
|
if (nature != pkm.Nature)
|
|
|
|
|
data.AddLine(GetInvalid(LTransferNature));
|
2019-05-21 00:05:53 +00:00
|
|
|
|
return;
|
2019-04-04 03:13:30 +00:00
|
|
|
|
}
|
2019-05-21 00:05:53 +00:00
|
|
|
|
if (met <= 2) // Not enough EXP to have every nature -- check for exclusions!
|
2019-04-04 03:13:30 +00:00
|
|
|
|
{
|
|
|
|
|
var pi = pkm.PersonalInfo;
|
|
|
|
|
var growth = pi.EXPGrowth;
|
|
|
|
|
var nature = pkm.Nature;
|
2019-05-21 00:05:53 +00:00
|
|
|
|
bool valid = VerifyVCNature(growth, nature);
|
|
|
|
|
if (!valid)
|
2019-04-04 03:13:30 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferNature));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool VerifyVCNature(int growth, int nature)
|
|
|
|
|
{
|
|
|
|
|
// exp % 25 with a limited amount of EXP does not allow for every nature
|
2019-10-08 01:40:09 +00:00
|
|
|
|
return growth switch
|
2019-04-04 03:13:30 +00:00
|
|
|
|
{
|
2019-10-08 01:40:09 +00:00
|
|
|
|
0 => // MediumFast -- Can't be Brave, Adamant, Naughty, Bold, Docile, or Relaxed
|
|
|
|
|
(nature < (int) Nature.Brave || nature > (int) Nature.Relaxed),
|
|
|
|
|
4 => // Fast -- Can't be Gentle, Sassy, Careful, Quirky, Hardy, Lonely, Brave, Adamant, Naughty, or Bold
|
|
|
|
|
(nature < (int) Nature.Gentle && nature > (int) Nature.Bold),
|
|
|
|
|
5 => // Slow -- Can't be Impish or Lax
|
|
|
|
|
(nature != (int) Nature.Impish && nature != (int) Nature.Lax),
|
|
|
|
|
_ => true
|
|
|
|
|
};
|
2019-04-04 03:13:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
public void VerifyTransferLegalityG3(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
2019-05-10 05:47:37 +00:00
|
|
|
|
if (pkm.Format == 4) // Pal Park (3->4)
|
|
|
|
|
{
|
2019-05-11 03:46:49 +00:00
|
|
|
|
if (pkm.Met_Location != Locations.Transfer3)
|
2019-05-10 05:47:37 +00:00
|
|
|
|
data.AddLine(GetInvalid(LEggLocationPalPark));
|
|
|
|
|
}
|
|
|
|
|
else // Transporter (4->5)
|
|
|
|
|
{
|
2019-05-11 03:46:49 +00:00
|
|
|
|
if (pkm.Met_Location != Locations.Transfer4)
|
2019-05-10 05:47:37 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferEggLocationTransporter));
|
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void VerifyTransferLegalityG4(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
|
|
|
|
int loc = pkm.Met_Location;
|
2019-05-11 03:46:49 +00:00
|
|
|
|
if (loc == Locations.Transfer4)
|
2018-07-02 02:17:37 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2019-05-10 05:47:37 +00:00
|
|
|
|
// Crown met location must be present if transferred via lock capsule
|
2018-07-02 02:17:37 +00:00
|
|
|
|
switch (pkm.Species)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
2019-06-01 17:22:49 +00:00
|
|
|
|
case (int)Species.Celebi:
|
2019-05-11 03:46:49 +00:00
|
|
|
|
if (loc != Locations.Transfer4_CelebiUnused && loc != Locations.Transfer4_CelebiUsed)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferMet));
|
2018-07-02 02:17:37 +00:00
|
|
|
|
break;
|
2019-06-01 17:22:49 +00:00
|
|
|
|
case (int)Species.Raikou:
|
|
|
|
|
case (int)Species.Entei:
|
|
|
|
|
case (int)Species.Suicune:
|
2019-05-11 03:46:49 +00:00
|
|
|
|
if (loc != Locations.Transfer4_CrownUnused && loc != Locations.Transfer4_CrownUsed)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferMet));
|
2018-07-02 02:17:37 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2018-09-01 21:11:12 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferEggLocationTransporter));
|
2018-07-02 02:17:37 +00:00
|
|
|
|
break;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-25 06:28:05 +00:00
|
|
|
|
public void VerifyTransferLegalityG8(LegalityAnalysis data)
|
|
|
|
|
{
|
|
|
|
|
var pkm = data.pkm;
|
|
|
|
|
int species = pkm.Species;
|
2019-11-16 01:34:18 +00:00
|
|
|
|
var pi = (PersonalInfoSWSH)PersonalTable.SWSH.GetFormeEntry(species, pkm.AltForm);
|
2019-11-28 19:51:23 +00:00
|
|
|
|
if (!pi.IsPresentInGame) // Can't transfer
|
2019-09-25 06:28:05 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferBad));
|
2019-11-28 19:51:23 +00:00
|
|
|
|
else if (pkm.GenNumber != 8) // Can't transfer yet
|
|
|
|
|
data.AddLine(GetInvalid(LTransferBad));
|
2020-01-10 02:44:45 +00:00
|
|
|
|
else if (pi.PokeDexIndex == 0 && data.EncounterMatch is EncounterEgg egg && !BreedGalarForeign.Contains(egg.Species)) // Can't breed cuz no transfer yet
|
2019-11-16 03:37:04 +00:00
|
|
|
|
data.AddLine(GetInvalid(LTransferBad));
|
2019-11-28 20:09:55 +00:00
|
|
|
|
else if (IsG8BanForm(pkm))
|
|
|
|
|
data.AddLine(GetInvalid(LTransferBad));
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 02:44:45 +00:00
|
|
|
|
private static readonly HashSet<int> BreedGalarForeign = new HashSet<int>
|
|
|
|
|
{
|
|
|
|
|
(int)Species.Slowpoke,
|
|
|
|
|
};
|
|
|
|
|
|
2020-01-06 02:46:30 +00:00
|
|
|
|
private static bool IsG8BanForm(PKM pkm)
|
2019-11-28 20:09:55 +00:00
|
|
|
|
{
|
|
|
|
|
return pkm.Species switch
|
|
|
|
|
{
|
2019-11-29 02:42:22 +00:00
|
|
|
|
(int)Species.Raichu when pkm.AltForm == 1 => true,
|
|
|
|
|
(int)Species.Vulpix when pkm.AltForm == 1 => true,
|
|
|
|
|
(int)Species.Ninetales when pkm.AltForm == 1 => true,
|
|
|
|
|
(int)Species.Diglett when pkm.AltForm == 1 => true,
|
|
|
|
|
(int)Species.Dugtrio when pkm.AltForm == 1 => true,
|
2019-11-28 20:09:55 +00:00
|
|
|
|
(int)Species.Meowth when pkm.AltForm == 1 => true,
|
|
|
|
|
(int)Species.Persian when pkm.AltForm == 1 => true,
|
|
|
|
|
(int)Species.Ponyta when pkm.AltForm == 0 => true,
|
|
|
|
|
(int)Species.Rapidash when pkm.AltForm == 0 => true,
|
2020-01-10 02:44:45 +00:00
|
|
|
|
(int)Species.Slowpoke when pkm.AltForm == 0 => true,
|
2019-11-28 20:09:55 +00:00
|
|
|
|
(int)Species.Farfetchd when pkm.AltForm == 0 => true,
|
|
|
|
|
(int)Species.Weezing when pkm.AltForm == 0 => true,
|
|
|
|
|
(int)Species.Corsola when pkm.AltForm == 0 => true,
|
2019-11-29 02:42:22 +00:00
|
|
|
|
(int)Species.Zigzagoon when pkm.AltForm == 0 => true,
|
|
|
|
|
(int)Species.Linoone when pkm.AltForm == 0 => true,
|
2019-11-29 18:03:35 +00:00
|
|
|
|
(int)Species.Shellos when pkm.AltForm == 0 => true,
|
|
|
|
|
(int)Species.Gastrodon when pkm.AltForm == 0 => true,
|
2019-11-28 20:09:55 +00:00
|
|
|
|
(int)Species.Darumaka when pkm.AltForm == 0 => true,
|
|
|
|
|
(int)Species.Darmanitan when pkm.AltForm == 0 => true,
|
2019-11-29 02:42:22 +00:00
|
|
|
|
(int)Species.Stunfisk when pkm.AltForm == 0 => true,
|
2019-11-28 20:09:55 +00:00
|
|
|
|
_ => false
|
|
|
|
|
};
|
2019-09-25 06:28:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-30 22:01:16 +00:00
|
|
|
|
public IEnumerable<CheckResult> VerifyVCEncounter(PKM pkm, IEncounterable encounter, ILocation transfer, IList<CheckMoveResult> Moves)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
// Check existing EncounterMatch
|
|
|
|
|
if (encounter is EncounterInvalid || transfer == null)
|
2019-09-10 07:21:51 +00:00
|
|
|
|
yield break; // Avoid duplicate invalid message
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
if (encounter is EncounterStatic v && (GameVersion.GBCartEraOnly.Contains(v.Version) || v.Version == GameVersion.VCEvents))
|
|
|
|
|
{
|
|
|
|
|
bool exceptions = false;
|
2019-12-09 01:39:19 +00:00
|
|
|
|
exceptions |= v.Version == GameVersion.VCEvents && encounter.Species == (int)Species.Mew && pkm.TID == 22796;
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (!exceptions)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
yield return GetInvalid(LG1GBEncounter);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pkm.Met_Location != transfer.Location)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
yield return GetInvalid(LTransferMetLocation);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (pkm.Egg_Location != transfer.EggLocation)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
yield return GetInvalid(LEggLocationNone);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
|
|
|
|
// Flag Moves that cannot be transferred
|
|
|
|
|
if (encounter is EncounterStatic s && s.Version == GameVersion.C && s.EggLocation == 256) // Dizzy Punch Gifts
|
2018-07-02 02:17:37 +00:00
|
|
|
|
FlagIncompatibleTransferMove(pkm, Moves, 146, 2); // can't have Dizzy Punch at all
|
2018-06-24 05:00:01 +00:00
|
|
|
|
|
2018-07-27 02:34:27 +00:00
|
|
|
|
bool checkShiny = pkm.VC2 || (pkm.TradebackStatus == TradebackType.WasTradeback && pkm.VC1);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (!checkShiny)
|
|
|
|
|
yield break;
|
2018-07-27 02:34:27 +00:00
|
|
|
|
|
2018-06-24 05:00:01 +00:00
|
|
|
|
if (pkm.Gender == 1) // female
|
|
|
|
|
{
|
|
|
|
|
if (pkm.PersonalInfo.Gender == 31 && pkm.IsShiny) // impossible gender-shiny
|
2018-09-01 21:11:12 +00:00
|
|
|
|
yield return GetInvalid(LEncStaticPIDShiny, CheckIdentifier.PID);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
2019-06-01 17:22:49 +00:00
|
|
|
|
else if (pkm.Species == (int)Species.Unown)
|
2018-06-24 05:00:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.AltForm != 8 && pkm.AltForm != 21 && pkm.IsShiny) // impossibly form-shiny (not I or V)
|
2018-09-01 21:11:12 +00:00
|
|
|
|
yield return GetInvalid(LEncStaticPIDShiny, CheckIdentifier.PID);
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-02 02:17:37 +00:00
|
|
|
|
|
|
|
|
|
private static void FlagIncompatibleTransferMove(PKM pkm, IList<CheckMoveResult> Moves, int move, int gen)
|
|
|
|
|
{
|
|
|
|
|
int index = Array.IndexOf(pkm.Moves, move);
|
|
|
|
|
if (index < 0)
|
|
|
|
|
return; // doesn't have move
|
|
|
|
|
|
|
|
|
|
var chk = Moves[index];
|
|
|
|
|
if (chk.Generation == gen) // not obtained from a future gen
|
2018-09-01 21:11:12 +00:00
|
|
|
|
Moves[index] = new CheckMoveResult(chk.Source, chk.Generation, Severity.Invalid, LTransferMove, CheckIdentifier.Move);
|
2018-07-02 02:17:37 +00:00
|
|
|
|
}
|
2018-06-24 05:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|