2016-03-12 17:16:41 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2017-03-25 17:24:56 +00:00
|
|
|
|
using static PKHeX.Core.LegalityCheckStrings;
|
2016-03-11 04:36:32 +00:00
|
|
|
|
|
2017-01-08 07:54:09 +00:00
|
|
|
|
namespace PKHeX.Core
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
2016-03-14 03:19:04 +00:00
|
|
|
|
public partial class LegalityAnalysis
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyGender()
|
2016-07-04 01:36:04 +00:00
|
|
|
|
{
|
2018-04-24 02:58:29 +00:00
|
|
|
|
var gr = pkm.PersonalInfo.Gender;
|
|
|
|
|
if (gr == 255 && pkm.Gender != 2)
|
2018-02-05 02:12:20 +00:00
|
|
|
|
{
|
|
|
|
|
// DP/HGSS shedinja glitch -- only generation 4 spawns
|
2018-04-24 02:58:29 +00:00
|
|
|
|
bool ignore = pkm.Format == 4 && pkm.Species == 292 && pkm.Met_Level != pkm.CurrentLevel;
|
2018-02-05 02:12:20 +00:00
|
|
|
|
if (!ignore)
|
|
|
|
|
AddLine(Severity.Invalid, V203, CheckIdentifier.Gender);
|
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
|
|
|
|
|
// Check for PID relationship to Gender & Nature if applicable
|
2017-09-04 02:51:29 +00:00
|
|
|
|
int gen = Info.Generation;
|
2017-03-25 17:24:56 +00:00
|
|
|
|
|
|
|
|
|
bool PIDGender = 3 <= gen && gen <= 5;
|
|
|
|
|
if (!PIDGender)
|
2018-04-24 02:58:29 +00:00
|
|
|
|
{
|
|
|
|
|
// Check fixed gender cases
|
|
|
|
|
if ((gr == 254 || gr == 0) && (gr == 0 ? 0 : 1) != pkm.Gender)
|
|
|
|
|
AddLine(Severity.Invalid, V203, CheckIdentifier.Gender);
|
2017-03-25 17:24:56 +00:00
|
|
|
|
return;
|
2018-04-24 02:58:29 +00:00
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
bool genderValid = pkm.IsGenderValid();
|
2018-02-05 02:12:20 +00:00
|
|
|
|
if (!genderValid)
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2018-02-05 02:12:20 +00:00
|
|
|
|
if (pkm.Format == 4 && pkm.Species == 292) // Shedinja glitch
|
|
|
|
|
{
|
|
|
|
|
// should match original gender
|
|
|
|
|
var gender = PKX.GetGenderFromPIDAndRatio(pkm.PID, 0x7F); // 50-50
|
|
|
|
|
if (gender == pkm.Gender)
|
|
|
|
|
genderValid = true;
|
|
|
|
|
}
|
|
|
|
|
else if (pkm.Format > 5 && (pkm.Species == 183 || pkm.Species == 184))
|
|
|
|
|
{
|
|
|
|
|
var gv = pkm.PID & 0xFF;
|
|
|
|
|
if (gv > 63 && pkm.Gender == 1) // evolved from azurill after transferring to keep gender
|
|
|
|
|
genderValid = true;
|
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
}
|
2018-04-24 02:58:29 +00:00
|
|
|
|
else
|
2017-10-20 03:56:59 +00:00
|
|
|
|
{
|
|
|
|
|
// check for mixed->fixed gender incompatibility by checking the gender of the original species
|
|
|
|
|
if (Legal.FixedGenderFromBiGender.Contains(EncounterMatch.Species) && pkm.Gender != 2) // shedinja
|
|
|
|
|
{
|
|
|
|
|
var gender = PKX.GetGenderFromPID(EncounterMatch.Species, pkm.EncryptionConstant);
|
|
|
|
|
genderValid &= gender == pkm.Gender; // gender must not be different from original
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
|
|
|
|
|
if (genderValid)
|
|
|
|
|
AddLine(Severity.Valid, V250, CheckIdentifier.Gender);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V251, CheckIdentifier.Gender);
|
|
|
|
|
|
|
|
|
|
bool PIDNature = gen != 5;
|
|
|
|
|
if (!PIDNature)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-05-04 06:14:34 +00:00
|
|
|
|
if (pkm.EncryptionConstant % 25 == pkm.Nature)
|
2017-03-25 17:24:56 +00:00
|
|
|
|
AddLine(Severity.Valid, V252, CheckIdentifier.Nature);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V253, CheckIdentifier.Nature);
|
2016-07-04 01:36:04 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyItem()
|
2017-02-26 15:55:22 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (!Legal.IsHeldItemAllowed(pkm.HeldItem, pkm.Format))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V204, CheckIdentifier.Form);
|
2017-04-10 22:59:16 +00:00
|
|
|
|
if (pkm.Format == 3 && pkm.HeldItem == 175)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyEReaderBerry();
|
2017-06-21 16:18:33 +00:00
|
|
|
|
if (pkm.IsEgg && pkm.HeldItem != 0)
|
2017-06-21 05:55:05 +00:00
|
|
|
|
AddLine(Severity.Invalid, V419, CheckIdentifier.Egg);
|
2017-04-10 22:59:16 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyEReaderBerry()
|
2017-04-10 22:59:16 +00:00
|
|
|
|
{
|
2017-04-11 02:00:58 +00:00
|
|
|
|
if (Legal.EReaderBerryIsEnigma) // no E-Reader berry data provided, can't hold berry.
|
2017-04-10 22:59:16 +00:00
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V204, CheckIdentifier.Form);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-11 02:00:58 +00:00
|
|
|
|
|
2017-04-10 22:59:16 +00:00
|
|
|
|
var matchUSA = Legal.EReaderBerriesNames_USA.Contains(Legal.EReaderBerryName);
|
|
|
|
|
var matchJP = Legal.EReaderBerriesNames_JP.Contains(Legal.EReaderBerryName);
|
2017-04-11 02:00:58 +00:00
|
|
|
|
if (!matchJP && !matchUSA) // Does not match any released E-Reader berry
|
2017-04-10 22:59:16 +00:00
|
|
|
|
AddLine(Severity.Invalid, V369, CheckIdentifier.Form);
|
2017-04-11 02:00:58 +00:00
|
|
|
|
else if (matchJP && !Legal.SavegameJapanese) // E-Reader is region locked
|
2017-04-10 22:59:16 +00:00
|
|
|
|
AddLine(Severity.Invalid, V370, CheckIdentifier.Form);
|
2017-04-11 02:00:58 +00:00
|
|
|
|
else if (matchUSA && Legal.SavegameJapanese) // E-Reader is region locked
|
2017-04-10 22:59:16 +00:00
|
|
|
|
AddLine(Severity.Invalid, V371, CheckIdentifier.Form);
|
2017-02-26 15:55:22 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyECPID()
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
2017-04-11 02:00:58 +00:00
|
|
|
|
if (pkm.Format >= 6)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyEC();
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch.Species == 265)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyECPIDWurmple();
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
if (pkm.PID == 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V207, CheckIdentifier.PID);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
|
2018-02-09 02:47:52 +00:00
|
|
|
|
if ((Info.Generation >= 6 || Info.Generation < 3 && pkm.Format >= 7) && pkm.PID == pkm.EncryptionConstant)
|
2017-04-11 02:00:58 +00:00
|
|
|
|
AddLine(Severity.Invalid, V208, CheckIdentifier.PID); // better to flag than 1:2^32 odds since RNG is not feasible to yield match
|
2016-03-11 04:36:32 +00:00
|
|
|
|
|
2017-06-03 22:16:24 +00:00
|
|
|
|
switch (EncounterMatch)
|
2017-04-02 13:39:39 +00:00
|
|
|
|
{
|
2017-06-03 22:16:24 +00:00
|
|
|
|
case EncounterStatic s:
|
2018-03-17 02:35:55 +00:00
|
|
|
|
if (!s.Shiny.IsValid(pkm))
|
2017-06-03 22:16:24 +00:00
|
|
|
|
AddLine(Severity.Invalid, V209, CheckIdentifier.Shiny);
|
2017-08-16 04:16:47 +00:00
|
|
|
|
|
|
|
|
|
// gen5 correlation
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Info.Generation != 5)
|
2017-08-16 04:16:47 +00:00
|
|
|
|
break;
|
|
|
|
|
if (s.Location == 75) // Entree Forest
|
|
|
|
|
break;
|
|
|
|
|
if (s.Gift || s.Roaming || s.Ability != 4)
|
|
|
|
|
break;
|
2017-12-18 23:25:40 +00:00
|
|
|
|
if (s is EncounterStaticPID p && p.NSparkle)
|
2017-08-16 04:16:47 +00:00
|
|
|
|
break;
|
|
|
|
|
VerifyG5PID_IDCorrelation();
|
2017-06-03 22:16:24 +00:00
|
|
|
|
break;
|
|
|
|
|
case EncounterSlot w:
|
|
|
|
|
if (pkm.IsShiny && w.Type == SlotType.HiddenGrotto)
|
|
|
|
|
AddLine(Severity.Invalid, V221, CheckIdentifier.Shiny);
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Info.Generation == 5 && w.Type != SlotType.HiddenGrotto)
|
2017-08-13 07:21:42 +00:00
|
|
|
|
VerifyG5PID_IDCorrelation();
|
2017-06-03 22:16:24 +00:00
|
|
|
|
break;
|
|
|
|
|
case PCD d: // fixed PID
|
|
|
|
|
if (d.Gift.PK.PID != 1 && pkm.EncryptionConstant != d.Gift.PK.PID)
|
|
|
|
|
AddLine(Severity.Invalid, V410, CheckIdentifier.Shiny);
|
|
|
|
|
break;
|
2017-04-02 13:39:39 +00:00
|
|
|
|
}
|
2017-04-11 02:00:58 +00:00
|
|
|
|
}
|
2017-08-13 07:21:42 +00:00
|
|
|
|
private void VerifyG5PID_IDCorrelation()
|
|
|
|
|
{
|
|
|
|
|
var pid = pkm.EncryptionConstant;
|
|
|
|
|
var result = (pid & 1) ^ (pid >> 31) ^ (pkm.TID & 1) ^ (pkm.SID & 1);
|
|
|
|
|
if (result != 0)
|
|
|
|
|
AddLine(Severity.Invalid, V411, CheckIdentifier.PID);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyECPIDWurmple()
|
2017-04-11 02:00:58 +00:00
|
|
|
|
{
|
2017-07-17 22:58:09 +00:00
|
|
|
|
uint evoVal = PKX.GetWurmpleEvoVal(pkm.EncryptionConstant);
|
2016-06-20 04:22:43 +00:00
|
|
|
|
|
2017-04-11 02:00:58 +00:00
|
|
|
|
if (pkm.Species == 265)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
AddLine(Severity.Valid, string.Format(V212, evoVal == 0 ? SpeciesStrings[267] : SpeciesStrings[269]), CheckIdentifier.EC);
|
2017-05-28 22:49:20 +00:00
|
|
|
|
else if (evoVal != Array.IndexOf(Legal.WurmpleEvolutions, pkm.Species) / 2)
|
2017-04-11 02:00:58 +00:00
|
|
|
|
AddLine(Severity.Invalid, V210, CheckIdentifier.EC);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyEC()
|
2017-04-11 02:00:58 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.EncryptionConstant == 0)
|
|
|
|
|
AddLine(Severity.Fishy, V201, CheckIdentifier.EC);
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (3 <= Info.Generation && Info.Generation <= 5)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyTransferEC();
|
2017-04-11 02:00:58 +00:00
|
|
|
|
else
|
2016-04-08 00:56:39 +00:00
|
|
|
|
{
|
2016-10-23 19:48:49 +00:00
|
|
|
|
int xor = pkm.TSV ^ pkm.PSV;
|
|
|
|
|
if (xor < 16 && xor >= 8 && (pkm.PID ^ 0x80000000) == pkm.EncryptionConstant)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V211, CheckIdentifier.EC);
|
2016-04-08 00:56:39 +00:00
|
|
|
|
}
|
2017-04-11 02:00:58 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyTransferEC()
|
2017-04-11 02:00:58 +00:00
|
|
|
|
{
|
2016-03-11 04:36:32 +00:00
|
|
|
|
// When transferred to Generation 6, the Encryption Constant is copied from the PID.
|
|
|
|
|
// The PID is then checked to see if it becomes shiny with the new Shiny rules (>>4 instead of >>3)
|
|
|
|
|
// If the PID is nonshiny->shiny, the top bit is flipped.
|
|
|
|
|
|
|
|
|
|
// Check to see if the PID and EC are properly configured.
|
2016-12-23 02:18:35 +00:00
|
|
|
|
bool xorPID = ((pkm.TID ^ pkm.SID ^ (int)(pkm.PID & 0xFFFF) ^ (int)(pkm.PID >> 16)) & ~0x7) == 8;
|
2016-03-11 04:36:32 +00:00
|
|
|
|
bool valid = xorPID
|
2016-10-23 19:48:49 +00:00
|
|
|
|
? pkm.EncryptionConstant == (pkm.PID ^ 0x8000000)
|
|
|
|
|
: pkm.EncryptionConstant == pkm.PID;
|
2016-03-11 04:36:32 +00:00
|
|
|
|
|
|
|
|
|
if (!valid)
|
2017-06-18 20:02:02 +00:00
|
|
|
|
AddLine(Severity.Invalid, xorPID ? V215 : V216, CheckIdentifier.EC);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
2017-09-23 18:46:10 +00:00
|
|
|
|
#region verifyLanguage
|
2017-09-23 23:24:22 +00:00
|
|
|
|
private bool VerifyLanguage()
|
2017-09-23 18:46:10 +00:00
|
|
|
|
{
|
|
|
|
|
int maxLanguageID = Legal.GetMaxLanguageID(Info.Generation);
|
2017-09-23 23:24:22 +00:00
|
|
|
|
|
|
|
|
|
// Language ID 6 is unused; flag if an impossible language is used
|
2017-10-23 04:01:08 +00:00
|
|
|
|
if (pkm.Language == (int)LanguageID.UNUSED_6 || pkm.Language > maxLanguageID)
|
2017-09-23 18:46:10 +00:00
|
|
|
|
{
|
2017-09-30 05:58:25 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V5, $"<={maxLanguageID}", pkm.Language), CheckIdentifier.Language);
|
2017-09-23 18:46:10 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-09-23 23:24:22 +00:00
|
|
|
|
|
|
|
|
|
// Korean Gen4 games can not trade with other Gen4 languages, but can use Pal Park with any Gen3 game/language.
|
2017-10-23 04:01:08 +00:00
|
|
|
|
if (pkm.Format == 4 && pkm.Gen4 &&
|
|
|
|
|
(pkm.Language == (int)LanguageID.Korean) ^ (Legal.SavegameLanguage == (int)LanguageID.Korean))
|
2017-09-23 23:24:22 +00:00
|
|
|
|
{
|
2017-10-23 04:01:08 +00:00
|
|
|
|
bool kor = pkm.Language == (int) LanguageID.Korean;
|
|
|
|
|
var currentpkm = kor ? V611 : V612;
|
|
|
|
|
var currentsav = kor ? V612 : V611;
|
2017-09-23 23:24:22 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V610, currentpkm, currentsav), CheckIdentifier.Language);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Korean Crystal does not exist
|
|
|
|
|
if (pkm.Version == (int)GameVersion.C && pkm.Korean)
|
2017-09-23 18:46:10 +00:00
|
|
|
|
{
|
2017-09-30 05:58:25 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V5, $"!={pkm.Language}", pkm.Language), CheckIdentifier.Language);
|
2017-09-23 18:46:10 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2017-04-07 00:41:25 +00:00
|
|
|
|
#region verifyNickname
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyNickname()
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
|
|
|
|
// If the Pokémon is not nicknamed, it should match one of the language strings.
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.Nickname.Length == 0)
|
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V2, CheckIdentifier.Nickname);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (pkm.Species > PKX.SpeciesLang[0].Length)
|
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Indeterminate, V3, CheckIdentifier.Nickname);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 04:42:05 +00:00
|
|
|
|
if (pkm.VC && pkm.IsNicknamed)
|
2017-01-27 05:35:26 +00:00
|
|
|
|
{
|
2017-09-08 04:42:05 +00:00
|
|
|
|
VerifyG1NicknameWithinBounds(pkm.Nickname);
|
2017-04-09 23:38:29 +00:00
|
|
|
|
}
|
2017-06-03 22:16:24 +00:00
|
|
|
|
else if (EncounterMatch is MysteryGift m)
|
2017-04-09 23:38:29 +00:00
|
|
|
|
{
|
2017-06-03 22:16:24 +00:00
|
|
|
|
if (pkm.IsNicknamed && !m.IsEgg)
|
2017-04-09 23:38:29 +00:00
|
|
|
|
AddLine(Severity.Fishy, V0, CheckIdentifier.Nickname);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 01:06:02 +00:00
|
|
|
|
if (!Encounter.Valid)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2017-09-23 23:24:22 +00:00
|
|
|
|
if (!VerifyLanguage())
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2017-04-22 20:04:12 +00:00
|
|
|
|
if (Type == typeof(EncounterTrade))
|
2016-03-27 00:23:53 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyNicknameTrade();
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-03-27 00:23:53 +00:00
|
|
|
|
}
|
2016-03-20 01:06:02 +00:00
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.IsEgg)
|
2016-03-16 04:15:40 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyNicknameEgg();
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-03-16 04:15:40 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
string nickname = pkm.Nickname.Replace("'", "’");
|
|
|
|
|
if (pkm.IsNicknamed)
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
2016-03-20 01:06:02 +00:00
|
|
|
|
for (int i = 0; i < PKX.SpeciesLang.Length; i++)
|
|
|
|
|
{
|
2017-10-06 05:37:45 +00:00
|
|
|
|
if (!PKX.SpeciesDict[i].TryGetValue(nickname, out int index))
|
2016-03-20 01:06:02 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
AddLine(Severity.Fishy, index == pkm.Species && i != pkm.Language
|
2017-03-21 07:18:38 +00:00
|
|
|
|
? V15
|
|
|
|
|
: V16, CheckIdentifier.Nickname);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-03-20 01:06:02 +00:00
|
|
|
|
}
|
2017-04-04 03:02:40 +00:00
|
|
|
|
if (nickname.Any(c => 0x4E00 <= c && c <= 0x9FFF)) // East Asian Scripts
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V222, CheckIdentifier.Nickname);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V17, CheckIdentifier.Nickname);
|
2016-03-16 01:56:18 +00:00
|
|
|
|
}
|
2017-02-13 01:00:03 +00:00
|
|
|
|
else if (pkm.Format < 3)
|
|
|
|
|
{
|
|
|
|
|
// pk1/pk2 IsNicknamed getter checks for match, logic should only reach here if matches.
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V18, CheckIdentifier.Nickname);
|
2017-02-13 01:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2016-03-16 01:56:18 +00:00
|
|
|
|
{
|
2016-07-11 05:22:55 +00:00
|
|
|
|
// Can't have another language name if it hasn't evolved or wasn't a language-traded egg.
|
2017-06-18 01:37:19 +00:00
|
|
|
|
bool evolved = Legal.IsNotBaseSpecies(pkm);
|
|
|
|
|
bool match = PKX.GetSpeciesNameGeneration(pkm.Species, pkm.Language, pkm.Format) == nickname;
|
2017-04-10 01:28:22 +00:00
|
|
|
|
if (pkm.WasTradedEgg || evolved)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
match |= !PKX.IsNicknamedAnyLanguage(pkm.Species, nickname, pkm.Format);
|
2017-04-10 01:28:22 +00:00
|
|
|
|
if (!match && pkm.Format == 5 && !pkm.IsNative) // transfer
|
|
|
|
|
{
|
|
|
|
|
if (evolved)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
match |= !PKX.IsNicknamedAnyLanguage(pkm.Species, nickname, 4);
|
2017-04-10 01:28:22 +00:00
|
|
|
|
else
|
2017-06-18 01:37:19 +00:00
|
|
|
|
match |= PKX.GetSpeciesNameGeneration(pkm.Species, pkm.Language, 4) == nickname;
|
2017-04-10 01:28:22 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
if (!match)
|
2017-02-21 06:03:07 +00:00
|
|
|
|
{
|
2017-12-12 00:01:24 +00:00
|
|
|
|
if (EncounterMatch is WC7 wc7 && wc7.CardID == 2046 && (pkm.SID << 16 | pkm.TID) == 0x79F57B49) // ash greninja
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V19, CheckIdentifier.Nickname);
|
2017-02-21 06:03:07 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V20, CheckIdentifier.Nickname);
|
2017-02-21 06:03:07 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V18, CheckIdentifier.Nickname);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
2017-09-06 06:31:24 +00:00
|
|
|
|
|
|
|
|
|
// Non-nicknamed strings have already been checked.
|
|
|
|
|
if (Legal.CheckWordFilter && pkm.IsNicknamed && WordFilter.IsFiltered(nickname, out string bad))
|
|
|
|
|
AddLine(Severity.Invalid, $"Wordfilter: {bad}", CheckIdentifier.Nickname);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyNicknameEgg()
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2017-05-10 04:11:13 +00:00
|
|
|
|
switch (pkm.Format)
|
|
|
|
|
{
|
|
|
|
|
case 4:
|
|
|
|
|
if (pkm.IsNicknamed) // gen4 doesn't use the nickname flag for eggs
|
|
|
|
|
AddLine(Severity.Invalid, V224, CheckIdentifier.Egg);
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
if (EncounterMatch is EncounterStatic ^ !pkm.IsNicknamed) // gen7 doesn't use for ingame gifts
|
|
|
|
|
AddLine(Severity.Invalid, pkm.IsNicknamed ? V224 : V12, CheckIdentifier.Egg);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (!pkm.IsNicknamed)
|
|
|
|
|
AddLine(Severity.Invalid, V12, CheckIdentifier.Egg);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (pkm.Format == 2 && pkm.IsEgg && !PKX.IsNicknamedAnyLanguage(0, pkm.Nickname, 2))
|
2017-06-13 05:16:20 +00:00
|
|
|
|
AddLine(Severity.Valid, V14, CheckIdentifier.Egg);
|
2017-09-04 02:51:29 +00:00
|
|
|
|
else if (PKX.GetSpeciesNameGeneration(0, pkm.Language, Info.Generation) != pkm.Nickname)
|
2017-03-25 17:24:56 +00:00
|
|
|
|
AddLine(Severity.Invalid, V13, CheckIdentifier.Egg);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V14, CheckIdentifier.Egg);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyNicknameTrade()
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2017-10-28 20:15:51 +00:00
|
|
|
|
switch (Info.Generation)
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2017-10-28 20:15:51 +00:00
|
|
|
|
case 1:
|
|
|
|
|
case 2: VerifyTrade12(); return;
|
2017-11-08 23:07:04 +00:00
|
|
|
|
case 3: VerifyTrade3(); return;
|
2017-10-28 20:15:51 +00:00
|
|
|
|
case 4: VerifyTrade4(); return;
|
2017-11-08 23:07:04 +00:00
|
|
|
|
case 5: VerifyTrade5(); return;
|
2017-10-28 20:15:51 +00:00
|
|
|
|
case 6: VerifyTrade6(); return;
|
|
|
|
|
case 7: VerifyTrade7(); return;
|
2017-03-25 17:24:56 +00:00
|
|
|
|
}
|
2017-10-28 20:15:51 +00:00
|
|
|
|
}
|
|
|
|
|
private void VerifyTrade12()
|
|
|
|
|
{
|
2017-12-12 00:01:24 +00:00
|
|
|
|
var et = (EncounterTrade)(EncounterOriginalGB ?? EncounterMatch);
|
|
|
|
|
if (et.TID != 0) // Gen2 Trade
|
2017-10-28 20:15:51 +00:00
|
|
|
|
return; // already checked all relevant properties when fetching with getValidEncounterTradeVC2
|
|
|
|
|
|
|
|
|
|
if (!EncounterGenerator.IsEncounterTrade1Valid(pkm))
|
|
|
|
|
AddLine(Severity.Invalid, V10, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
2017-10-29 02:51:55 +00:00
|
|
|
|
private void VerifyTrade3()
|
|
|
|
|
{
|
|
|
|
|
if (pkm.FRLG)
|
2018-04-13 04:22:04 +00:00
|
|
|
|
{
|
|
|
|
|
int lang = pkm.Language;
|
|
|
|
|
if (EncounterMatch.Species == 124) // Jynx
|
|
|
|
|
lang = DetectTradeLanguageG3DANTAEJynx(pkm, lang);
|
|
|
|
|
VerifyTradeTable(Encounters3.TradeFRLG, Encounters3.TradeGift_FRLG, lang);
|
|
|
|
|
}
|
2017-10-29 02:51:55 +00:00
|
|
|
|
else
|
|
|
|
|
VerifyTradeTable(Encounters3.TradeRSE, Encounters3.TradeGift_RSE);
|
|
|
|
|
}
|
2017-10-28 20:15:51 +00:00
|
|
|
|
private void VerifyTrade4()
|
|
|
|
|
{
|
|
|
|
|
if (pkm.TID == 1000)
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2017-10-28 20:15:51 +00:00
|
|
|
|
VerifyTrade4Ranch();
|
2017-03-25 17:24:56 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-10-28 20:15:51 +00:00
|
|
|
|
if (pkm.HGSS)
|
2017-11-28 07:21:14 +00:00
|
|
|
|
{
|
|
|
|
|
int lang = pkm.Language;
|
2017-11-29 06:26:31 +00:00
|
|
|
|
if (EncounterMatch.Species == 25) // Pikachu
|
2018-04-07 19:34:06 +00:00
|
|
|
|
{
|
2017-11-29 06:26:31 +00:00
|
|
|
|
lang = DetectTradeLanguageG4SurgePikachu(pkm, lang);
|
2018-04-07 19:34:06 +00:00
|
|
|
|
// flag korean magikarp on gen4 saves since the pkm.Language is German
|
|
|
|
|
if (pkm.Format == 4 && lang == (int)LanguageID.Korean && Legal.SavegameLanguage != (int)LanguageID.Korean)
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V610, V611, V612), CheckIdentifier.Language);
|
|
|
|
|
}
|
2017-11-28 07:21:14 +00:00
|
|
|
|
VerifyTradeTable(Encounters4.TradeHGSS, Encounters4.TradeGift_HGSS, lang);
|
|
|
|
|
}
|
2017-11-29 06:26:31 +00:00
|
|
|
|
else // DPPt
|
2017-10-29 02:02:18 +00:00
|
|
|
|
{
|
2017-11-29 06:26:31 +00:00
|
|
|
|
int lang = pkm.Language;
|
2017-10-29 02:02:18 +00:00
|
|
|
|
if (EncounterMatch.Species == 129) // Magikarp
|
2018-04-07 19:34:06 +00:00
|
|
|
|
{
|
2017-11-29 06:26:31 +00:00
|
|
|
|
lang = DetectTradeLanguageG4MeisterMagikarp(pkm, lang);
|
2018-04-07 19:34:06 +00:00
|
|
|
|
// flag korean magikarp on gen4 saves since the pkm.Language is German
|
|
|
|
|
if (pkm.Format == 4 && lang == (int)LanguageID.Korean && Legal.SavegameLanguage != (int)LanguageID.Korean)
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V610, V611, V612), CheckIdentifier.Language);
|
|
|
|
|
}
|
2017-12-01 02:13:30 +00:00
|
|
|
|
else if (!pkm.Pt && lang == 1) // DP English origin are Japanese lang
|
|
|
|
|
{
|
|
|
|
|
int index = Array.IndexOf(Encounters4.TradeGift_DPPt, EncounterMatch);
|
|
|
|
|
if (Encounters4.TradeDPPt[1][index] != pkm.Nickname) // not japanese
|
|
|
|
|
lang = 2; // English
|
|
|
|
|
}
|
2017-11-29 06:26:31 +00:00
|
|
|
|
VerifyTradeTable(Encounters4.TradeDPPt, Encounters4.TradeGift_DPPt, lang);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-13 04:22:04 +00:00
|
|
|
|
private static int DetectTradeLanguageG3DANTAEJynx(PKM pk, int lang)
|
|
|
|
|
{
|
|
|
|
|
if (lang != (int)LanguageID.Italian)
|
|
|
|
|
return lang;
|
|
|
|
|
|
|
|
|
|
if (pk.Version == (int) GameVersion.LG)
|
|
|
|
|
lang = (int)LanguageID.English; // translation error; OT was not localized => same as English
|
|
|
|
|
return lang;
|
|
|
|
|
}
|
2017-11-29 06:26:31 +00:00
|
|
|
|
private static int DetectTradeLanguageG4MeisterMagikarp(PKM pkm, int lang)
|
|
|
|
|
{
|
|
|
|
|
if (lang == (int)LanguageID.English)
|
|
|
|
|
return (int)LanguageID.German;
|
|
|
|
|
|
|
|
|
|
// All have German, regardless of origin version.
|
|
|
|
|
// Detect which language they originated from... roughly.
|
|
|
|
|
var table = Encounters4.TradeDPPt;
|
|
|
|
|
for (int i = 0; i < table.Length; i++)
|
|
|
|
|
{
|
2017-12-01 02:13:30 +00:00
|
|
|
|
if (table[i].Length == 0)
|
2017-11-29 06:26:31 +00:00
|
|
|
|
continue;
|
|
|
|
|
// Nick @ 3, OT @ 7
|
|
|
|
|
if (table[i][7] != pkm.OT_Name)
|
|
|
|
|
continue;
|
|
|
|
|
lang = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-04-07 19:34:06 +00:00
|
|
|
|
if (lang == 2) // possible collision with FR/ES/DE. Check nickname
|
|
|
|
|
return pkm.Nickname == table[3][3] ? (int)LanguageID.French : (int)LanguageID.Spanish; // Spanish is same as English
|
2017-11-29 06:26:31 +00:00
|
|
|
|
|
|
|
|
|
return lang;
|
|
|
|
|
}
|
|
|
|
|
private static int DetectTradeLanguageG4SurgePikachu(PKM pkm, int lang)
|
|
|
|
|
{
|
|
|
|
|
if (lang == (int)LanguageID.French)
|
|
|
|
|
return (int)LanguageID.English;
|
|
|
|
|
|
|
|
|
|
// All have English, regardless of origin version.
|
|
|
|
|
// Detect which language they originated from... roughly.
|
|
|
|
|
var table = Encounters4.TradeHGSS;
|
|
|
|
|
for (int i = 0; i < table.Length; i++)
|
|
|
|
|
{
|
2017-12-01 02:13:30 +00:00
|
|
|
|
if (table[i].Length == 0)
|
2017-11-29 06:26:31 +00:00
|
|
|
|
continue;
|
|
|
|
|
// Nick @ 6, OT @ 18
|
|
|
|
|
if (table[i][18] != pkm.OT_Name)
|
|
|
|
|
continue;
|
|
|
|
|
lang = i;
|
|
|
|
|
break;
|
2017-10-29 02:02:18 +00:00
|
|
|
|
}
|
2017-11-29 06:26:31 +00:00
|
|
|
|
if (lang == 2) // possible collision with ES/IT. Check nickname
|
|
|
|
|
return pkm.Nickname == table[4][6] ? (int)LanguageID.Italian : (int)LanguageID.Spanish;
|
|
|
|
|
|
|
|
|
|
return lang;
|
2017-10-28 20:15:51 +00:00
|
|
|
|
}
|
|
|
|
|
private void VerifyTrade5()
|
|
|
|
|
{
|
|
|
|
|
// Trades for JPN games have language ID of 0, not 1.
|
|
|
|
|
if (pkm.BW)
|
2017-09-16 00:43:31 +00:00
|
|
|
|
{
|
2017-10-29 04:43:47 +00:00
|
|
|
|
int lang = pkm.Language;
|
|
|
|
|
if (pkm.Format == 5 && lang == (int)LanguageID.Japanese)
|
2017-10-23 04:01:08 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V5, 0, (int)LanguageID.Japanese), CheckIdentifier.Language);
|
2017-09-16 00:43:31 +00:00
|
|
|
|
|
2017-10-29 04:43:47 +00:00
|
|
|
|
lang = Math.Max(lang, 1);
|
|
|
|
|
VerifyTradeTable(Encounters5.TradeBW, Encounters5.TradeGift_BW, lang);
|
2017-03-28 09:02:46 +00:00
|
|
|
|
}
|
2017-10-28 20:15:51 +00:00
|
|
|
|
else // B2W2
|
2017-10-29 04:43:47 +00:00
|
|
|
|
{
|
|
|
|
|
if (Encounters5.TradeGift_B2W2_YancyCurtis.Contains(EncounterMatch))
|
|
|
|
|
VerifyTradeOTOnly(pkm.OT_Gender == 0 ? Encounters5.TradeOT_B2W2_M : Encounters5.TradeOT_B2W2_F);
|
|
|
|
|
else
|
|
|
|
|
VerifyTradeTable(Encounters5.TradeB2W2, Encounters5.TradeGift_B2W2);
|
|
|
|
|
}
|
2017-10-28 20:15:51 +00:00
|
|
|
|
}
|
|
|
|
|
private void VerifyTrade6()
|
|
|
|
|
{
|
|
|
|
|
if (pkm.XY)
|
2017-10-29 04:43:47 +00:00
|
|
|
|
VerifyTradeTable(Encounters6.TradeXY, Encounters6.TradeGift_XY, pkm.Language);
|
2017-10-28 20:15:51 +00:00
|
|
|
|
else if (pkm.AO)
|
2017-10-29 04:43:47 +00:00
|
|
|
|
VerifyTradeTable(Encounters6.TradeAO, Encounters6.TradeGift_AO, pkm.Language);
|
2017-10-28 20:15:51 +00:00
|
|
|
|
}
|
|
|
|
|
private void VerifyTrade7()
|
|
|
|
|
{
|
|
|
|
|
if (pkm.SM)
|
2017-10-29 06:04:02 +00:00
|
|
|
|
VerifyTradeTable(Encounters7.TradeSM, Encounters7.TradeGift_SM, pkm.Language);
|
2017-10-28 20:15:51 +00:00
|
|
|
|
else if (pkm.USUM)
|
2017-10-29 06:04:02 +00:00
|
|
|
|
VerifyTradeTable(Encounters7.TradeUSUM, Encounters7.TradeGift_USUM, pkm.Language);
|
2017-10-28 20:15:51 +00:00
|
|
|
|
}
|
2017-10-29 04:43:47 +00:00
|
|
|
|
private void VerifyTrade4Ranch() => VerifyTradeOTOnly(Encounters4.RanchOTNames);
|
|
|
|
|
|
|
|
|
|
private void VerifyTradeTable(string[][] ots, EncounterTrade[] table) => VerifyTradeTable(ots, table, pkm.Language);
|
|
|
|
|
private void VerifyTradeTable(string[][] ots, EncounterTrade[] table, int language)
|
2017-10-28 20:15:51 +00:00
|
|
|
|
{
|
2017-11-28 07:21:14 +00:00
|
|
|
|
var validOT = language >= ots.Length ? ots[0] : ots[language];
|
2017-10-28 20:15:51 +00:00
|
|
|
|
var index = Array.IndexOf(table, EncounterMatch);
|
|
|
|
|
VerifyTradeOTNick(validOT, index);
|
2017-10-29 02:02:18 +00:00
|
|
|
|
}
|
2017-10-29 04:43:47 +00:00
|
|
|
|
private void VerifyTradeOTOnly(string[] validOT)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.IsNicknamed)
|
|
|
|
|
AddLine(Severity.Invalid, V9, CheckIdentifier.Nickname);
|
|
|
|
|
int lang = pkm.Language;
|
2017-11-17 15:57:55 +00:00
|
|
|
|
if (validOT.Length <= lang)
|
2017-10-29 04:43:47 +00:00
|
|
|
|
AddLine(Severity.Invalid, V8, CheckIdentifier.Trainer);
|
|
|
|
|
else if (validOT[lang] != pkm.OT_Name)
|
|
|
|
|
AddLine(Severity.Invalid, V10, CheckIdentifier.Trainer);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V11, CheckIdentifier.Nickname);
|
|
|
|
|
}
|
2017-10-28 20:15:51 +00:00
|
|
|
|
private void VerifyTradeOTNick(string[] validOT, int index)
|
|
|
|
|
{
|
2017-03-25 17:24:56 +00:00
|
|
|
|
if (validOT.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Indeterminate, V7, CheckIdentifier.Trainer);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (index == -1 || validOT.Length < index * 2)
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Indeterminate, V8, CheckIdentifier.Trainer);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string nick = validOT[index];
|
|
|
|
|
string OT = validOT[validOT.Length / 2 + index];
|
|
|
|
|
|
2017-11-22 16:11:53 +00:00
|
|
|
|
if (nick != pkm.Nickname
|
|
|
|
|
&& !(nick == "Quacklin’" && pkm.Nickname == "Quacklin'") // apostrophe farfetch'd edge case
|
|
|
|
|
&& ((EncounterTrade)EncounterMatch).IsNicknamed) // trades that are not nicknamed (but are present in a table with others being named)
|
2017-10-29 04:43:47 +00:00
|
|
|
|
AddLine(Severity.Invalid, V9, CheckIdentifier.Nickname);
|
2017-03-25 17:24:56 +00:00
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V11, CheckIdentifier.Nickname);
|
2017-10-29 02:02:18 +00:00
|
|
|
|
|
|
|
|
|
if (OT != pkm.OT_Name)
|
|
|
|
|
AddLine(Severity.Invalid, V10, CheckIdentifier.Trainer);
|
2017-03-25 17:24:56 +00:00
|
|
|
|
}
|
2017-04-07 00:41:25 +00:00
|
|
|
|
#endregion
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyEVs()
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
2016-10-23 19:48:49 +00:00
|
|
|
|
var evs = pkm.EVs;
|
2016-03-14 03:19:04 +00:00
|
|
|
|
int sum = evs.Sum();
|
2017-04-12 03:55:34 +00:00
|
|
|
|
if (sum > 0 && pkm.IsEgg)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V22, CheckIdentifier.EVs);
|
2017-06-27 03:12:49 +00:00
|
|
|
|
if (pkm.Format >= 3 && sum > 510)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V25, CheckIdentifier.EVs);
|
2017-04-12 03:55:34 +00:00
|
|
|
|
if (pkm.Format >= 6 && evs.Any(ev => ev > 252))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V26, CheckIdentifier.EVs);
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (pkm.Format == 4 && pkm.Gen4 && EncounterMatch.LevelMin == 100)
|
2017-04-10 12:11:07 +00:00
|
|
|
|
{
|
2017-04-12 03:55:34 +00:00
|
|
|
|
// Cannot EV train at level 100 -- Certain events are distributed at level 100.
|
|
|
|
|
if (evs.Any(ev => ev > 100)) // EVs can only be increased by vitamins to a max of 100.
|
2017-04-10 12:11:07 +00:00
|
|
|
|
AddLine(Severity.Invalid, V367, CheckIdentifier.EVs);
|
|
|
|
|
}
|
2017-06-25 00:24:32 +00:00
|
|
|
|
else if (pkm.Format < 5)
|
2017-06-19 04:13:53 +00:00
|
|
|
|
{
|
2017-10-07 15:23:05 +00:00
|
|
|
|
// In Generations I and II, when a Pokémon is taken out of the Day Care, its experience will lower to the minimum value for its current level.
|
|
|
|
|
if (pkm.Format < 3) // can abuse daycare for EV training without EXP gain
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const int maxEV = 100; // Vitamin Max
|
2017-06-19 04:13:53 +00:00
|
|
|
|
if (PKX.GetEXP(EncounterMatch.LevelMin, pkm.Species) == pkm.EXP && evs.Any(ev => ev > maxEV))
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V418, maxEV), CheckIdentifier.EVs);
|
|
|
|
|
}
|
2017-04-12 03:55:34 +00:00
|
|
|
|
|
|
|
|
|
// Only one of the following can be true: 0, 508, and x%6!=0
|
2017-06-22 03:47:07 +00:00
|
|
|
|
if (sum == 0 && !EncounterMatch.IsWithinRange(pkm))
|
2017-04-12 03:55:34 +00:00
|
|
|
|
AddLine(Severity.Fishy, V23, CheckIdentifier.EVs);
|
|
|
|
|
else if (sum == 508)
|
|
|
|
|
AddLine(Severity.Fishy, V24, CheckIdentifier.EVs);
|
|
|
|
|
else if (evs[0] != 0 && evs.All(ev => evs[0] == ev))
|
|
|
|
|
AddLine(Severity.Fishy, V27, CheckIdentifier.EVs);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyIVs()
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
2018-03-09 05:18:32 +00:00
|
|
|
|
if (EncounterMatch is EncounterStatic s)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2018-03-09 05:18:32 +00:00
|
|
|
|
if (s.FlawlessIVCount != 0 && pkm.IVs.Count(iv => iv == 31) < s.FlawlessIVCount)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2018-03-09 05:18:32 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V28, s.FlawlessIVCount), CheckIdentifier.IVs);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-01 05:06:11 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot w)
|
2017-01-01 01:20:13 +00:00
|
|
|
|
{
|
2017-12-19 00:17:21 +00:00
|
|
|
|
bool force2 = w.Type == SlotType.FriendSafari || w.Generation == 7 && pkm.AbilityNumber == 4;
|
2017-12-01 05:06:11 +00:00
|
|
|
|
if (force2 && pkm.IVs.Count(iv => iv == 31) < 2)
|
2017-01-01 01:20:13 +00:00
|
|
|
|
{
|
2017-12-03 02:54:41 +00:00
|
|
|
|
AddLine(Severity.Invalid, w.Type == SlotType.FriendSafari ? V29 : string.Format(V28, 2), CheckIdentifier.IVs);
|
2017-01-01 01:20:13 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-28 05:40:21 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift g)
|
2017-02-02 05:27:14 +00:00
|
|
|
|
{
|
|
|
|
|
int[] IVs;
|
2017-05-28 05:40:21 +00:00
|
|
|
|
switch (g.Format)
|
2017-02-02 05:27:14 +00:00
|
|
|
|
{
|
|
|
|
|
case 7: IVs = ((WC7)EncounterMatch).IVs; break;
|
2017-03-10 04:27:03 +00:00
|
|
|
|
case 6: IVs = ((WC6)EncounterMatch).IVs; break;
|
|
|
|
|
case 5: IVs = ((PGF)EncounterMatch).IVs; break;
|
2017-02-02 05:27:14 +00:00
|
|
|
|
default: IVs = null; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IVs != null)
|
|
|
|
|
{
|
|
|
|
|
var pkIVs = pkm.IVs;
|
2018-03-03 00:17:14 +00:00
|
|
|
|
var ivflag = IVs.FirstOrDefault(iv => (byte)(iv - 0xFC) < 3);
|
|
|
|
|
if (ivflag == 0) // Random IVs
|
|
|
|
|
{
|
|
|
|
|
bool valid = true;
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
if (IVs[i] <= 31 && IVs[i] != pkIVs[i])
|
|
|
|
|
valid = false;
|
|
|
|
|
if (!valid)
|
|
|
|
|
AddLine(Severity.Invalid, V30, CheckIdentifier.IVs);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int IVCount = ivflag - 0xFB; // IV2/IV3
|
|
|
|
|
if (pkIVs.Count(iv => iv == 31) < IVCount)
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V28, IVCount), CheckIdentifier.IVs);
|
|
|
|
|
}
|
2017-02-02 05:27:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.IVs.Sum() == 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V31, CheckIdentifier.IVs);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else if (pkm.IVs[0] < 30 && pkm.IVs.All(iv => pkm.IVs[0] == iv))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V32, CheckIdentifier.IVs);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyDVs()
|
2017-02-13 01:00:03 +00:00
|
|
|
|
{
|
|
|
|
|
// todo
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
#region VerifyOT
|
|
|
|
|
private void VerifyOT()
|
2016-03-11 04:36:32 +00:00
|
|
|
|
{
|
2017-04-22 20:04:12 +00:00
|
|
|
|
if (Type == typeof(EncounterTrade))
|
2017-06-10 00:52:20 +00:00
|
|
|
|
return; // Already matches Encounter information
|
|
|
|
|
|
|
|
|
|
if (EncounterMatch is MysteryGift g && !g.IsEgg)
|
|
|
|
|
return; // Already matches Encounter information
|
|
|
|
|
|
2017-12-18 23:25:40 +00:00
|
|
|
|
if (EncounterMatch is EncounterStaticPID s && s.NSparkle)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
return; // Already checked by VerifyMisc
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2017-10-16 01:11:20 +00:00
|
|
|
|
var ot = pkm.OT_Name;
|
|
|
|
|
if (ot.Length == 0)
|
|
|
|
|
AddLine(Severity.Invalid, V106, CheckIdentifier.Trainer);
|
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.TID == 0 && pkm.SID == 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V33, CheckIdentifier.Trainer);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
else if (pkm.VC)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.SID != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V34, CheckIdentifier.Trainer);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else if (pkm.TID == pkm.SID)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V35, CheckIdentifier.Trainer);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else if (pkm.TID == 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V36, CheckIdentifier.Trainer);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else if (pkm.SID == 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V37, CheckIdentifier.Trainer);
|
2017-10-16 01:11:20 +00:00
|
|
|
|
else if (pkm.TID == 12345 && pkm.SID == 54321 || ot.StartsWith("PKHeX"))
|
2017-06-18 23:47:23 +00:00
|
|
|
|
AddLine(Severity.Fishy, V417, CheckIdentifier.Trainer);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
|
|
|
|
|
if (pkm.VC)
|
2018-01-26 17:19:20 +00:00
|
|
|
|
VerifyOTG1();
|
2017-09-06 06:31:24 +00:00
|
|
|
|
|
|
|
|
|
if (Legal.CheckWordFilter)
|
|
|
|
|
{
|
2017-10-16 01:11:20 +00:00
|
|
|
|
if (WordFilter.IsFiltered(ot, out string bad))
|
2017-10-19 01:18:23 +00:00
|
|
|
|
AddLine(Severity.Invalid, $"Wordfilter: {bad}", CheckIdentifier.Trainer);
|
2017-09-06 06:31:24 +00:00
|
|
|
|
if (WordFilter.IsFiltered(pkm.HT_Name, out bad))
|
2017-10-19 01:18:23 +00:00
|
|
|
|
AddLine(Severity.Invalid, $"Wordfilter: {bad}", CheckIdentifier.Trainer);
|
2017-09-06 06:31:24 +00:00
|
|
|
|
}
|
2017-02-13 01:00:03 +00:00
|
|
|
|
}
|
2018-01-26 17:19:20 +00:00
|
|
|
|
private void VerifyOTG1()
|
2017-02-13 01:00:03 +00:00
|
|
|
|
{
|
|
|
|
|
string tr = pkm.OT_Name;
|
2017-01-27 05:35:26 +00:00
|
|
|
|
|
2017-09-08 04:42:05 +00:00
|
|
|
|
VerifyG1OTWithinBounds(tr);
|
2017-10-25 01:27:40 +00:00
|
|
|
|
if (EncounterMatch is EncounterStatic s && (s.Version == GameVersion.Stadium || s.Version == GameVersion.Stadium2))
|
2017-09-08 04:42:05 +00:00
|
|
|
|
VerifyG1OTStadium(tr);
|
|
|
|
|
|
2017-02-13 01:00:03 +00:00
|
|
|
|
if (pkm.Species == 151)
|
|
|
|
|
{
|
2017-10-04 07:14:50 +00:00
|
|
|
|
if (tr != "GF" && tr != "ゲーフリ" || pkm.TID != 22796) // if there are more events with special OTs, may be worth refactoring
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V39, CheckIdentifier.Trainer);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
}
|
2017-05-28 17:35:41 +00:00
|
|
|
|
|
2018-01-26 03:25:10 +00:00
|
|
|
|
if (pkm.OT_Gender == 1 && (pkm.Format == 2 && pkm.Met_Location == 0 || pkm.Format > 2 && pkm.VC1))
|
2017-05-28 17:35:41 +00:00
|
|
|
|
AddLine(Severity.Invalid, V408, CheckIdentifier.Trainer);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
2017-09-08 04:42:05 +00:00
|
|
|
|
private void VerifyG1OTWithinBounds(string str)
|
|
|
|
|
{
|
|
|
|
|
if (StringConverter.GetIsG1English(str))
|
|
|
|
|
{
|
2018-04-07 19:34:06 +00:00
|
|
|
|
if (str.Length > 7 && !((EncounterOriginalGB ?? EncounterMatch) is EncounterTrade)) // OT already verified; GER shuckle has 8 chars
|
2017-09-08 04:42:05 +00:00
|
|
|
|
AddLine(Severity.Invalid, V38, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
|
|
|
|
else if (StringConverter.GetIsG1Japanese(str))
|
|
|
|
|
{
|
|
|
|
|
if (str.Length > 5)
|
|
|
|
|
AddLine(Severity.Invalid, V38, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
2018-01-27 17:45:33 +00:00
|
|
|
|
else if (pkm.Korean && StringConverter.GetIsG2Korean(str))
|
2017-09-11 05:30:41 +00:00
|
|
|
|
{
|
|
|
|
|
if (str.Length > 5)
|
|
|
|
|
AddLine(Severity.Invalid, V38, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
2017-09-08 04:42:05 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V421, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private void VerifyG1NicknameWithinBounds(string str)
|
|
|
|
|
{
|
|
|
|
|
if (StringConverter.GetIsG1English(str))
|
|
|
|
|
{
|
|
|
|
|
if (str.Length > 10)
|
|
|
|
|
AddLine(Severity.Invalid, V1, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
|
|
|
|
else if (StringConverter.GetIsG1Japanese(str))
|
|
|
|
|
{
|
|
|
|
|
if (str.Length > 5)
|
|
|
|
|
AddLine(Severity.Invalid, V1, CheckIdentifier.Trainer);
|
2018-01-27 17:45:33 +00:00
|
|
|
|
}
|
|
|
|
|
else if (pkm.Korean && StringConverter.GetIsG2Korean(str))
|
|
|
|
|
{
|
|
|
|
|
if (str.Length > 5)
|
|
|
|
|
AddLine(Severity.Invalid, V38, CheckIdentifier.Trainer);
|
2017-09-08 04:42:05 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V422, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private void VerifyG1OTStadium(string tr)
|
|
|
|
|
{
|
2017-10-25 01:27:40 +00:00
|
|
|
|
bool jp = pkm.Japanese;
|
2017-09-08 04:42:05 +00:00
|
|
|
|
bool valid = GetIsStadiumOTIDValid(jp, tr);
|
|
|
|
|
if (!valid)
|
|
|
|
|
AddLine(Severity.Invalid, V402, CheckIdentifier.Trainer);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, jp ? V404 : V403, CheckIdentifier.Trainer);
|
|
|
|
|
}
|
2017-08-16 23:57:17 +00:00
|
|
|
|
private bool GetIsStadiumOTIDValid(bool jp, string tr)
|
|
|
|
|
{
|
|
|
|
|
if (jp)
|
|
|
|
|
return tr == "スタジアム" && pkm.TID == 1999;
|
2017-10-25 01:27:40 +00:00
|
|
|
|
return tr == (Info.Generation == 1 ? "STADIUM" : "Stadium") && pkm.TID == 2000;
|
2017-08-16 23:57:17 +00:00
|
|
|
|
}
|
2017-04-07 00:41:25 +00:00
|
|
|
|
#endregion
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyHyperTraining()
|
2016-11-11 10:31:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.Format < 7)
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return; // No Hyper Training before Gen7
|
2016-11-11 10:31:50 +00:00
|
|
|
|
|
|
|
|
|
var IVs = new[] { pkm.IV_HP, pkm.IV_ATK, pkm.IV_DEF, pkm.IV_SPA, pkm.IV_SPD, pkm.IV_SPE };
|
|
|
|
|
var HTs = new[] { pkm.HT_HP, pkm.HT_ATK, pkm.HT_DEF, pkm.HT_SPA, pkm.HT_SPD, pkm.HT_SPE };
|
2016-11-11 11:23:38 +00:00
|
|
|
|
|
|
|
|
|
if (HTs.Any(ht => ht) && pkm.CurrentLevel != 100)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V40, CheckIdentifier.IVs);
|
2016-11-11 11:23:38 +00:00
|
|
|
|
|
2016-11-11 10:31:50 +00:00
|
|
|
|
if (IVs.All(iv => iv == 31) && HTs.Any(ht => ht))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V41, CheckIdentifier.IVs);
|
2016-11-11 10:31:50 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < 6; i++) // Check individual IVs
|
|
|
|
|
{
|
2017-09-05 01:55:15 +00:00
|
|
|
|
if (!HTs[i] || IVs[i] != 31)
|
|
|
|
|
continue;
|
|
|
|
|
AddLine(Severity.Invalid, V42, CheckIdentifier.IVs);
|
|
|
|
|
break;
|
2016-11-11 10:31:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
#region VerifyEncounter
|
|
|
|
|
private void VerifyFormFriendSafari()
|
2017-02-13 01:00:03 +00:00
|
|
|
|
{
|
2017-03-20 07:03:31 +00:00
|
|
|
|
switch (pkm.Species)
|
|
|
|
|
{
|
|
|
|
|
case 670: // Floette
|
|
|
|
|
case 671: // Florges
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (!new[] { 0, 1, 3 }.Contains(pkm.AltForm)) // 0/1/3 - RBY
|
|
|
|
|
AddLine(Severity.Invalid, V64, CheckIdentifier.Form);
|
2017-03-20 07:03:31 +00:00
|
|
|
|
break;
|
|
|
|
|
case 710: // Pumpkaboo
|
|
|
|
|
case 711: // Goregeist
|
2017-03-25 17:24:56 +00:00
|
|
|
|
if (pkm.AltForm != 0) // Average
|
2017-05-28 04:17:53 +00:00
|
|
|
|
AddLine(Severity.Invalid, V6, CheckIdentifier.Form);
|
2017-03-20 07:03:31 +00:00
|
|
|
|
break;
|
|
|
|
|
case 586: // Sawsbuck
|
|
|
|
|
if (pkm.AltForm != 0)
|
2017-05-28 04:17:53 +00:00
|
|
|
|
AddLine(Severity.Invalid, V65, CheckIdentifier.Form);
|
2017-03-20 07:03:31 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyEncounterType()
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
{
|
2017-04-24 00:53:22 +00:00
|
|
|
|
if (!Encounter.Valid)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-04-22 20:04:12 +00:00
|
|
|
|
EncounterType type = EncounterType.None;
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
// Encounter type data is only stored for gen 4 encounters
|
|
|
|
|
// All eggs have encounter type none, even if they are from static encounters
|
2017-04-23 04:00:06 +00:00
|
|
|
|
if (pkm.Gen4 && !pkm.WasEgg)
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
{
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot w)
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
// If there is more than one slot, the get wild encounter have filter for the pkm type encounter like safari/sports ball
|
2017-05-28 04:17:53 +00:00
|
|
|
|
type = w.TypeEncounter;
|
|
|
|
|
if (EncounterMatch is EncounterStaticTyped s)
|
|
|
|
|
type = s.TypeEncounter;
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
}
|
2017-04-23 04:00:06 +00:00
|
|
|
|
|
Encounter Type fix and detection of pokemon that should have evolve on trade (#1105)
* Detect encounter trades that evolve on trade and have not been evolved
Detect generation 1 pokemon with special catch rates : krabby trade and Pokemon Stadium
Detect generation 1 pokemon that evolve on trade and have been traded but not evolved
Detect pokemon with tradeback status any but with only encounters from the other GB generation, that means they are WasTradeback
Detect pokemon with moves from the other GB generation, change tradebackstatus to WasTradeback
* Fix dppt surfing and fishing encounter type, is is surfing because the battle background is the same as other surfingfishing encounters
Fix headbutt encounter type, the encounter type depends on the battle background used when battle a pokemon, for headbutt it changes with the player tile, is the player is in a city it will be building encounter, in a grass tile tall grass, in water it is surfingfishing and cave inside a cave. Some locations have more than one possible encounter type, for example routes with trees near the grass, near the water and near non-combat tiles.
Also added slot type headbutt special for the special trees, those trees are all in routes and are only adjacent to non-combat tiles
* Fix encounter type for missing areas with multiple grass encounters types: Mt Coronet, Mt Silver Cave and Stark Mountain (Issue # 1095)
* Fixes and typos
* Check for non-japanese e-reader pokemon, is unreleased
2017-05-01 15:07:20 +00:00
|
|
|
|
if (!type.Contains(pkm.EncounterType))
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
AddLine(Severity.Invalid, V381, CheckIdentifier.Encounter);
|
2017-04-23 04:00:06 +00:00
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V380, CheckIdentifier.Encounter);
|
Special Eggs improvement and Generation 4 Encounter Type legal analysis (#1083)
* Ignore relearn level 2-100 moves from Phione
* Cave encounter types DPPt
* Generation 4 EncounterType filter and validation
Not every generation 4 static encounter have yet their encounter type defined, i temporally included Any to those encounters
Generation 4 roaaming static encounters have been splitted in two, grass and surf
* Added new legality texts
* Added unreleased event DP Darkai, added check for surf in jhoto route 45, is impossible
Moved unreleased DP locations to valid Platinum locations only
* Improved generation 3 special egg check.
Only check special egg if pokemon knows any of the special egg moves, also in that case do check for normal egg before special egg
because special eggs will explicitly check for normal egg moves but normal eggs will not check special egg moves, it will improve the error output
* Clean up
* Fix gen 5 pokemon from issue #1011
Those pokemon have generation 4 static gift encounters and also wild encounters, the analysis was selecting the static encounter, but if there is a valid wild encounter and the static encounter does not match the pokemon ball the willd encounter should be selected instead
Also move the transfer legality to check it before the static encounters and make that check to work like generation 3 transfer legality
* Another fix for Issue 1011, suppress temporally OT and pokemon name analysis for generations 3 to 5 instead of format 3 to 5, there is no data stored yet to make those analysis
* Do not make wild encounters prevail static encounter if the pokemon was an egg
* Changed type of WildEncounter variable to EncounterSlot[]
* Fix Jhoto Route 45 to avoid return error with fishing encounters
2017-04-22 18:49:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyTransferLegalityG3()
|
2017-03-26 22:37:56 +00:00
|
|
|
|
{
|
2017-11-23 05:45:30 +00:00
|
|
|
|
if (pkm.Format == 4 && pkm.Met_Location != Legal.Transfer3) // Pal Park
|
2017-03-31 07:04:29 +00:00
|
|
|
|
AddLine(Severity.Invalid, V60, CheckIdentifier.Encounter);
|
2017-11-23 05:45:30 +00:00
|
|
|
|
if (pkm.Format != 4 && pkm.Met_Location != Legal.Transfer4)
|
2017-03-31 07:04:29 +00:00
|
|
|
|
AddLine(Severity.Invalid, V61, CheckIdentifier.Encounter);
|
2017-03-26 22:37:56 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyTransferLegalityG4()
|
2017-04-25 00:42:15 +00:00
|
|
|
|
{
|
|
|
|
|
// Transfer Legality
|
|
|
|
|
int loc = pkm.Met_Location;
|
|
|
|
|
if (loc != 30001) // PokéTransfer
|
|
|
|
|
{
|
|
|
|
|
// Crown
|
|
|
|
|
switch (pkm.Species)
|
|
|
|
|
{
|
|
|
|
|
case 251: // Celebi
|
2017-11-23 05:45:30 +00:00
|
|
|
|
if (loc != Legal.Transfer4_CelebiUnused && loc != Legal.Transfer4_CelebiUsed)
|
2017-04-25 00:42:15 +00:00
|
|
|
|
AddLine(Severity.Invalid, V351, CheckIdentifier.Encounter);
|
|
|
|
|
break;
|
|
|
|
|
case 243: // Raikou
|
|
|
|
|
case 244: // Entei
|
|
|
|
|
case 245: // Suicune
|
2017-11-23 05:45:30 +00:00
|
|
|
|
if (loc != Legal.Transfer4_CrownUnused && loc != Legal.Transfer4_CrownUsed)
|
2017-04-25 00:42:15 +00:00
|
|
|
|
AddLine(Severity.Invalid, V351, CheckIdentifier.Encounter);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
AddLine(Severity.Invalid, V61, CheckIdentifier.Encounter);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-26 03:17:42 +00:00
|
|
|
|
private static IEnumerable<CheckResult> VerifyVCEncounter(PKM pkm, IEncounterable encounter, ILocation transfer, IList<CheckMoveResult> Moves)
|
2017-01-27 05:35:26 +00:00
|
|
|
|
{
|
2017-02-14 02:06:01 +00:00
|
|
|
|
// Check existing EncounterMatch
|
2017-07-09 15:47:17 +00:00
|
|
|
|
if (encounter == null || transfer == null)
|
2017-05-28 04:17:53 +00:00
|
|
|
|
yield break; // Avoid duplicate invaild message
|
2017-02-15 06:06:15 +00:00
|
|
|
|
|
2018-01-11 00:16:35 +00:00
|
|
|
|
if (encounter is EncounterStatic v && (GameVersion.GBCartEraOnly.Contains(v.Version) || v.Version == GameVersion.VCEvents))
|
2017-02-15 06:06:15 +00:00
|
|
|
|
{
|
|
|
|
|
bool exceptions = false;
|
2018-01-11 00:16:35 +00:00
|
|
|
|
exceptions |= v.Version == GameVersion.VCEvents && encounter.Species == 151 && pkm.TID == 22796;
|
2017-02-15 06:06:15 +00:00
|
|
|
|
if (!exceptions)
|
2017-05-28 04:17:53 +00:00
|
|
|
|
yield return new CheckResult(Severity.Invalid, V79, CheckIdentifier.Encounter);
|
2017-02-15 06:06:15 +00:00
|
|
|
|
}
|
2017-03-10 04:27:03 +00:00
|
|
|
|
|
2017-07-09 15:47:17 +00:00
|
|
|
|
if (pkm.Met_Location != transfer.Location)
|
2017-05-28 04:17:53 +00:00
|
|
|
|
yield return new CheckResult(Severity.Invalid, V81, CheckIdentifier.Encounter);
|
2017-07-09 15:47:17 +00:00
|
|
|
|
if (pkm.Egg_Location != transfer.EggLocation)
|
2017-05-28 04:17:53 +00:00
|
|
|
|
yield return new CheckResult(Severity.Invalid, V59, CheckIdentifier.Encounter);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
|
2018-01-26 03:17:42 +00:00
|
|
|
|
// Flag Moves that cannot be transferred
|
2018-01-30 17:38:45 +00:00
|
|
|
|
if (encounter is EncounterStatic s && s.Version == GameVersion.C && s.EggLocation == 256) // Dizzy Punch Gifts
|
2018-01-26 03:17:42 +00:00
|
|
|
|
{
|
|
|
|
|
// can't have Dizzy Punch at all
|
|
|
|
|
int index = Array.IndexOf(pkm.Moves, 146); // Dizzy Punch
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
var chk = Moves[index];
|
|
|
|
|
if (chk.Generation == 2) // not obtained from a future gen
|
|
|
|
|
Moves[index] = new CheckMoveResult(chk.Source, chk.Generation, Severity.Invalid, V82, CheckIdentifier.Move);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-11 00:16:35 +00:00
|
|
|
|
|
|
|
|
|
bool checkShiny = pkm.VC2 || pkm.TradebackStatus == TradebackType.WasTradeback && pkm.VC1;
|
|
|
|
|
if (!checkShiny)
|
|
|
|
|
yield break;
|
|
|
|
|
if (pkm.Gender == 1) // female
|
|
|
|
|
{
|
|
|
|
|
if (pkm.PersonalInfo.Gender == 31 && pkm.IsShiny) // impossible gender-shiny
|
|
|
|
|
yield return new CheckResult(Severity.Invalid, V209, CheckIdentifier.PID);
|
|
|
|
|
}
|
|
|
|
|
else if (pkm.Species == 201) // unown
|
|
|
|
|
{
|
|
|
|
|
if (pkm.AltForm != 8 && pkm.AltForm != 21 && pkm.IsShiny) // impossibly form-shiny (not I or V)
|
|
|
|
|
yield return new CheckResult(Severity.Invalid, V209, CheckIdentifier.PID);
|
|
|
|
|
}
|
2017-01-27 05:35:26 +00:00
|
|
|
|
}
|
2017-04-07 00:41:25 +00:00
|
|
|
|
#endregion
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyLevel()
|
2016-03-19 05:49:21 +00:00
|
|
|
|
{
|
2017-06-19 04:13:53 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift gift)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-06-29 05:09:26 +00:00
|
|
|
|
if (gift.Level != pkm.Met_Level && pkm.HasOriginalMetLocation)
|
2016-11-13 23:40:34 +00:00
|
|
|
|
{
|
2017-06-29 05:09:26 +00:00
|
|
|
|
switch (gift)
|
|
|
|
|
{
|
2017-06-30 02:32:29 +00:00
|
|
|
|
case WC3 wc3 when wc3.Met_Level == pkm.Met_Level:
|
2017-06-29 05:09:26 +00:00
|
|
|
|
break;
|
|
|
|
|
case WC7 wc7 when wc7.MetLevel == pkm.Met_Level:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
AddLine(new CheckResult(Severity.Invalid, V83, CheckIdentifier.Level));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-13 23:40:34 +00:00
|
|
|
|
}
|
2017-06-19 04:13:53 +00:00
|
|
|
|
if (gift.Level > pkm.CurrentLevel)
|
|
|
|
|
{
|
|
|
|
|
AddLine(new CheckResult(Severity.Invalid, V84, CheckIdentifier.Level));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-12-12 01:13:59 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2017-03-19 23:52:56 +00:00
|
|
|
|
if (pkm.IsEgg)
|
|
|
|
|
{
|
2017-06-19 04:13:53 +00:00
|
|
|
|
int elvl = Legal.GetEggHatchLevel(pkm);
|
|
|
|
|
if (elvl != pkm.CurrentLevel)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V52, elvl), CheckIdentifier.Level);
|
2017-06-19 04:13:53 +00:00
|
|
|
|
return;
|
2017-03-19 23:52:56 +00:00
|
|
|
|
}
|
2017-06-19 04:13:53 +00:00
|
|
|
|
|
|
|
|
|
int lvl = pkm.CurrentLevel;
|
|
|
|
|
if (lvl < pkm.Met_Level)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V85, CheckIdentifier.Level);
|
2017-06-22 03:47:07 +00:00
|
|
|
|
else if (!EncounterMatch.IsWithinRange(pkm) && lvl != 100 && pkm.EXP == PKX.GetEXP(lvl, pkm.Species))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Fishy, V87, CheckIdentifier.Level);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V88, CheckIdentifier.Level);
|
2018-01-26 17:19:20 +00:00
|
|
|
|
}
|
|
|
|
|
private void VerifyLevelG1()
|
|
|
|
|
{
|
|
|
|
|
if (pkm.IsEgg)
|
|
|
|
|
{
|
|
|
|
|
int elvl = Legal.GetEggHatchLevel(pkm);
|
|
|
|
|
if (elvl != pkm.CurrentLevel)
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V52, elvl), CheckIdentifier.Level);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (pkm.Met_Location != 0) // crystal
|
|
|
|
|
{
|
|
|
|
|
int lvl = pkm.CurrentLevel;
|
|
|
|
|
if (lvl < pkm.Met_Level)
|
|
|
|
|
AddLine(Severity.Invalid, V85, CheckIdentifier.Level);
|
|
|
|
|
}
|
Encounter Type fix and detection of pokemon that should have evolve on trade (#1105)
* Detect encounter trades that evolve on trade and have not been evolved
Detect generation 1 pokemon with special catch rates : krabby trade and Pokemon Stadium
Detect generation 1 pokemon that evolve on trade and have been traded but not evolved
Detect pokemon with tradeback status any but with only encounters from the other GB generation, that means they are WasTradeback
Detect pokemon with moves from the other GB generation, change tradebackstatus to WasTradeback
* Fix dppt surfing and fishing encounter type, is is surfing because the battle background is the same as other surfingfishing encounters
Fix headbutt encounter type, the encounter type depends on the battle background used when battle a pokemon, for headbutt it changes with the player tile, is the player is in a city it will be building encounter, in a grass tile tall grass, in water it is surfingfishing and cave inside a cave. Some locations have more than one possible encounter type, for example routes with trees near the grass, near the water and near non-combat tiles.
Also added slot type headbutt special for the special trees, those trees are all in routes and are only adjacent to non-combat tiles
* Fix encounter type for missing areas with multiple grass encounters types: Mt Coronet, Mt Silver Cave and Stark Mountain (Issue # 1095)
* Fixes and typos
* Check for non-japanese e-reader pokemon, is unreleased
2017-05-01 15:07:20 +00:00
|
|
|
|
|
2017-05-01 15:25:20 +00:00
|
|
|
|
// There is no way to prevent a gen1 trade evolution as held items (everstone) did not exist.
|
|
|
|
|
// Machoke, Graveler, Haunter and Kadabra captured in the second phase evolution, excluding in-game trades, are already checked
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (pkm.Format <= 2 && Type != typeof (EncounterTrade) && EncounterMatch.Species == pkm.Species && Legal.Trade_Evolution1.Contains(EncounterMatch.Species))
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyG1TradeEvo();
|
2017-05-01 15:25:20 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyG1TradeEvo()
|
2017-05-01 15:25:20 +00:00
|
|
|
|
{
|
2017-06-07 03:10:05 +00:00
|
|
|
|
var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && Legal.IsOutsider(pkm)) || Legal.IsTradedKadabraG1(pkm);
|
2017-05-01 15:25:20 +00:00
|
|
|
|
if (!mustevolve)
|
|
|
|
|
return;
|
|
|
|
|
// Pokemon have been traded but it is not evolved, trade evos are sequential dex numbers
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var unevolved = SpeciesStrings[pkm.Species];
|
|
|
|
|
var evolved = SpeciesStrings[pkm.Species + 1];
|
2017-05-01 15:25:20 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V405, unevolved, evolved), CheckIdentifier.Level);
|
2016-03-19 05:49:21 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
#region VerifyMedals
|
|
|
|
|
private void VerifyMedals()
|
2016-11-08 16:43:57 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.Format < 6)
|
|
|
|
|
return;
|
2017-03-25 17:24:56 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyMedalsRegular();
|
|
|
|
|
VerifyMedalsEvent();
|
2017-03-25 17:24:56 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyMedalsRegular()
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2017-04-15 19:22:29 +00:00
|
|
|
|
uint data = BitConverter.ToUInt32(pkm.Data, 0x2C);
|
|
|
|
|
if ((data & 3) != 0) // 2 unused flags
|
|
|
|
|
AddLine(Severity.Invalid, V98, CheckIdentifier.Training);
|
2017-06-21 04:57:00 +00:00
|
|
|
|
int TrainCount = pkm.SuperTrainingMedalCount();
|
2017-04-15 19:22:29 +00:00
|
|
|
|
|
2016-11-08 16:43:57 +00:00
|
|
|
|
if (pkm.IsEgg && TrainCount > 0)
|
2017-06-21 04:57:00 +00:00
|
|
|
|
AddLine(Severity.Invalid, V89, CheckIdentifier.Training);
|
2017-09-04 02:51:29 +00:00
|
|
|
|
else if (TrainCount > 0 && Info.Generation > 6)
|
2017-06-21 04:57:00 +00:00
|
|
|
|
AddLine(Severity.Invalid, V90, CheckIdentifier.Training);
|
2017-01-25 17:17:20 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (pkm.Format >= 7)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.SecretSuperTrainingUnlocked)
|
2017-06-21 04:57:00 +00:00
|
|
|
|
AddLine(Severity.Invalid, V91, CheckIdentifier.Training);
|
2017-01-25 17:17:20 +00:00
|
|
|
|
if (pkm.SecretSuperTrainingComplete)
|
2017-06-21 04:57:00 +00:00
|
|
|
|
AddLine(Severity.Invalid, V92, CheckIdentifier.Training);
|
2017-01-25 17:17:20 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (TrainCount == 30 ^ pkm.SecretSuperTrainingComplete)
|
2017-06-21 04:57:00 +00:00
|
|
|
|
AddLine(Severity.Invalid, V93, CheckIdentifier.Training);
|
2017-01-25 17:17:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
}
|
2017-06-21 04:57:00 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyMedalsEvent()
|
2017-03-25 17:24:56 +00:00
|
|
|
|
{
|
2017-04-15 19:22:29 +00:00
|
|
|
|
byte data = pkm.Data[0x3A];
|
|
|
|
|
if ((data & 0xC0) != 0) // 2 unused flags highest bits
|
|
|
|
|
AddLine(Severity.Invalid, V98, CheckIdentifier.Training);
|
|
|
|
|
|
|
|
|
|
int TrainCount = 0;
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
{
|
|
|
|
|
if ((data & 1) != 0)
|
|
|
|
|
TrainCount++;
|
|
|
|
|
data >>= 1;
|
|
|
|
|
}
|
|
|
|
|
if (pkm.IsEgg && TrainCount > 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{ AddLine(Severity.Invalid, V89, CheckIdentifier.Training); }
|
2017-09-04 02:51:29 +00:00
|
|
|
|
else if (TrainCount > 0 && Info.Generation > 6)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{ AddLine(Severity.Invalid, V90, CheckIdentifier.Training); }
|
2017-04-15 19:22:29 +00:00
|
|
|
|
else if (TrainCount > 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{ AddLine(Severity.Fishy, V94, CheckIdentifier.Training); }
|
2016-11-08 16:43:57 +00:00
|
|
|
|
}
|
2017-04-07 00:41:25 +00:00
|
|
|
|
#endregion
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyRibbons()
|
2016-03-20 22:20:11 +00:00
|
|
|
|
{
|
|
|
|
|
if (!Encounter.Valid)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-09-17 19:21:23 +00:00
|
|
|
|
|
2017-06-20 04:43:44 +00:00
|
|
|
|
// Check Unobtainable Ribbons
|
|
|
|
|
var encounterContent = (EncounterMatch as MysteryGift)?.Content ?? EncounterMatch;
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.IsEgg)
|
2016-09-03 15:10:22 +00:00
|
|
|
|
{
|
2017-09-06 03:32:07 +00:00
|
|
|
|
if (RibbonVerifier.GetIncorrectRibbonsEgg(pkm, encounterContent))
|
|
|
|
|
AddLine(Severity.Invalid, V603, CheckIdentifier.Ribbon);
|
2017-06-20 04:43:44 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-18 02:11:01 +00:00
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
List<string> result = RibbonVerifier.GetIncorrectRibbons(pkm, encounterContent, Info.Generation);
|
2017-12-05 04:16:54 +00:00
|
|
|
|
if (result.Count != 0)
|
2017-09-04 02:51:29 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Join(Environment.NewLine, result.Where(s => !string.IsNullOrEmpty(s))), CheckIdentifier.Ribbon);
|
|
|
|
|
else
|
2017-06-20 04:43:44 +00:00
|
|
|
|
AddLine(Severity.Valid, V602, CheckIdentifier.Ribbon);
|
2017-06-21 04:57:00 +00:00
|
|
|
|
}
|
2017-04-18 02:11:01 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyCXD()
|
2017-04-30 23:53:54 +00:00
|
|
|
|
{
|
2017-06-03 22:16:24 +00:00
|
|
|
|
if (EncounterMatch is EncounterStatic)
|
2017-06-21 00:57:23 +00:00
|
|
|
|
VerifyCXDStarterCorrelation(Info.PIDIV);
|
2017-05-03 02:08:16 +00:00
|
|
|
|
else if (pkm.WasEgg) // can't obtain eggs in CXD
|
|
|
|
|
AddLine(Severity.Invalid, V80, CheckIdentifier.Encounter); // invalid encounter
|
2017-05-28 17:35:41 +00:00
|
|
|
|
|
|
|
|
|
if (pkm.OT_Gender == 1)
|
|
|
|
|
AddLine(Severity.Invalid, V407, CheckIdentifier.Trainer);
|
2017-04-30 23:53:54 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyCXDStarterCorrelation(PIDIV pidiv)
|
2017-05-13 07:03:35 +00:00
|
|
|
|
{
|
2017-06-10 06:13:41 +00:00
|
|
|
|
if (pidiv.Type != PIDType.CXD)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-11-02 04:12:44 +00:00
|
|
|
|
bool valid;
|
|
|
|
|
switch (EncounterMatch.Species)
|
2017-05-13 07:03:35 +00:00
|
|
|
|
{
|
2017-11-02 04:12:44 +00:00
|
|
|
|
case 133:
|
|
|
|
|
valid = LockFinder.IsXDStarterValid(pidiv.OriginSeed, pkm.TID, pkm.SID); break;
|
|
|
|
|
case 196: case 197:
|
|
|
|
|
valid = pidiv.Type == PIDType.CXD_ColoStarter; break;
|
2017-05-13 07:03:35 +00:00
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-11-02 04:12:44 +00:00
|
|
|
|
if (!valid)
|
|
|
|
|
AddLine(Severity.Invalid, V400, CheckIdentifier.PID);
|
2017-05-13 07:03:35 +00:00
|
|
|
|
}
|
2017-04-30 23:53:54 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyAbility()
|
2016-03-21 15:01:08 +00:00
|
|
|
|
{
|
2016-10-29 06:41:22 +00:00
|
|
|
|
int[] abilities = pkm.PersonalInfo.Abilities;
|
2017-03-18 23:17:42 +00:00
|
|
|
|
if (abilities[1] == 0)
|
|
|
|
|
abilities[1] = abilities[0];
|
2016-10-23 19:48:49 +00:00
|
|
|
|
int abilval = Array.IndexOf(abilities, pkm.Ability);
|
2016-03-21 15:01:08 +00:00
|
|
|
|
if (abilval < 0)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V107, CheckIdentifier.Ability);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-03-21 15:01:08 +00:00
|
|
|
|
|
2017-04-14 23:24:41 +00:00
|
|
|
|
bool? AbilityUnchanged = true;
|
|
|
|
|
// 3 states flag: true for unchanged, false for changed, null for uncertain/allowing PID mismatch
|
|
|
|
|
// if true, check encounter ability
|
|
|
|
|
// if true or false, check PID/AbilityNumber
|
|
|
|
|
if (3 <= pkm.Format && pkm.Format <= 5 && abilities[0] != abilities[1]) // 3-5 and have 2 distinct ability now
|
2017-06-18 01:37:19 +00:00
|
|
|
|
AbilityUnchanged = VerifyAbilityPreCapsule(abilities, abilval);
|
2017-04-14 23:24:41 +00:00
|
|
|
|
|
2017-10-21 03:10:56 +00:00
|
|
|
|
if (Encounter.Valid)
|
2016-03-23 02:47:13 +00:00
|
|
|
|
{
|
2018-04-18 03:48:14 +00:00
|
|
|
|
if (EncounterMatch is PCD d)
|
|
|
|
|
{
|
|
|
|
|
if (VerifyAbilityPCD(d, AbilityUnchanged, abilities))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else // Check Ability Mismatches
|
|
|
|
|
{
|
|
|
|
|
int? EncounterAbility = (EncounterMatch as EncounterStatic)?.Ability ??
|
|
|
|
|
(EncounterMatch as EncounterTrade)?.Ability ??
|
|
|
|
|
(EncounterMatch as EncounterLink)?.Ability;
|
|
|
|
|
|
|
|
|
|
if (EncounterAbility != null && VerifySetAbility(EncounterAbility, AbilityUnchanged, abilities, abilval))
|
|
|
|
|
return; // result added via VerifySetAbility
|
|
|
|
|
}
|
2017-09-04 02:51:29 +00:00
|
|
|
|
switch (Info.Generation)
|
2017-03-22 23:47:14 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
case 5: VerifyAbility5(abilities); break;
|
|
|
|
|
case 6: VerifyAbility6(abilities); break;
|
|
|
|
|
case 7: VerifyAbility7(abilities); break;
|
2016-03-31 02:55:27 +00:00
|
|
|
|
}
|
2016-03-23 02:47:13 +00:00
|
|
|
|
}
|
2016-03-22 04:50:39 +00:00
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (3 <= Info.Generation && Info.Generation <= 4 && pkm.AbilityNumber == 4)
|
2017-04-12 03:11:58 +00:00
|
|
|
|
AddLine(Severity.Invalid, V112, CheckIdentifier.Ability);
|
2017-04-14 23:24:41 +00:00
|
|
|
|
else if (AbilityUnchanged != null && abilities[pkm.AbilityNumber >> 1] != pkm.Ability)
|
|
|
|
|
AddLine(Severity.Invalid, pkm.Format < 6 ? V113 : V114, CheckIdentifier.Ability);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-04-12 03:55:34 +00:00
|
|
|
|
AddLine(Severity.Valid, V115, CheckIdentifier.Ability);
|
2016-03-21 15:01:08 +00:00
|
|
|
|
}
|
2018-04-18 03:48:14 +00:00
|
|
|
|
private bool VerifyAbilityPCD(PCD pcd, bool? abilityUnchanged, int[] abilities)
|
|
|
|
|
{
|
|
|
|
|
if (pcd.Species == pkm.Species && pkm.Ability == pcd.Gift.PK.Ability) // Edge case (PID ability gift mismatch)
|
|
|
|
|
AddLine(Severity.Valid, V115, CheckIdentifier.Ability);
|
|
|
|
|
else if (pkm.Format >= 6 && abilities[0] == abilities[1] && pkm.AbilityNumber == 1)
|
|
|
|
|
AddLine(Severity.Valid, V115, CheckIdentifier.Ability); // gen3-5 transfer with same ability -> 1st ability that matches
|
|
|
|
|
else if (pkm.Format >= 6 && abilities[0] != abilities[1] && pkm.AbilityNumber < 4) // Ability Capsule can change between 1/2
|
|
|
|
|
AddLine(Severity.Valid, V109, CheckIdentifier.Ability);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!(abilityUnchanged ?? false))
|
|
|
|
|
return false;
|
|
|
|
|
AddLine(Severity.Invalid, V223, CheckIdentifier.Ability);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private bool VerifySetAbility(int? EncounterAbility, bool? AbilityUnchanged, int[] abilities, int abilval)
|
2017-05-09 03:35:06 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.AbilityNumber == 4 && EncounterAbility != 4)
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V108, CheckIdentifier.Ability);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(AbilityUnchanged ?? false) || EncounterAbility == 0 || pkm.AbilityNumber == EncounterAbility)
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-05-24 03:10:57 +00:00
|
|
|
|
if (EncounterMatch is EncounterTrade z && EncounterAbility == 1 << abilval && z.Species == pkm.Species) // Edge case (Static PID?)
|
2017-05-09 03:35:06 +00:00
|
|
|
|
AddLine(Severity.Valid, V115, CheckIdentifier.Ability);
|
2017-10-21 03:10:56 +00:00
|
|
|
|
else if (pkm.Format >= 6 && abilities[0] != abilities[1] && pkm.AbilityNumber < 4 && EncounterAbility != 4) // Ability Capsule can change between 1/2
|
2017-05-24 03:10:57 +00:00
|
|
|
|
AddLine(Severity.Valid, V109, CheckIdentifier.Ability);
|
2017-05-09 03:35:06 +00:00
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V223, CheckIdentifier.Ability);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private bool? VerifyAbilityPreCapsule(int[] abilities, int abilval)
|
2017-04-12 03:11:58 +00:00
|
|
|
|
{
|
2017-04-15 02:55:40 +00:00
|
|
|
|
// CXD pokemon could have any ability without maching PID
|
2017-04-14 23:24:41 +00:00
|
|
|
|
if (pkm.Version == (int)GameVersion.CXD && pkm.Format == 3)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
// gen3 native or gen4/5 origin
|
|
|
|
|
if (pkm.Format == 3 || !pkm.InhabitedGeneration(3))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// Evovled in gen4/5
|
|
|
|
|
if (pkm.Species > Legal.MaxSpeciesID_3)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// gen3Species will be zero for pokemon with illegal gen 3 encounters, like Infernape with gen 3 "origin"
|
2017-06-21 00:57:23 +00:00
|
|
|
|
var gen3Species = Info.EvoChainsAllGens[3].FirstOrDefault()?.Species ?? 0;
|
2017-04-14 23:24:41 +00:00
|
|
|
|
if (gen3Species == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// Fall through when gen3 pkm transferred to gen4/5
|
2017-06-18 01:37:19 +00:00
|
|
|
|
return VerifyAbilityGen3Transfer(abilities, abilval, gen3Species);
|
2017-04-12 03:11:58 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private bool? VerifyAbilityGen3Transfer(int[] abilities, int abilval, int Species_g3)
|
2017-04-12 03:11:58 +00:00
|
|
|
|
{
|
2017-04-14 23:24:41 +00:00
|
|
|
|
var abilities_g3 = PersonalTable.E[Species_g3].Abilities.Where(a => a != 0).Distinct().ToArray();
|
2017-05-09 03:35:06 +00:00
|
|
|
|
if (abilities_g3.Length == 2) // Excluding Colosseum/XD, a gen3 pkm must match PID if it has 2 unique abilities
|
2017-04-12 03:11:58 +00:00
|
|
|
|
return pkm.Version != (int)GameVersion.CXD;
|
2017-04-14 23:24:41 +00:00
|
|
|
|
|
2017-06-21 00:57:23 +00:00
|
|
|
|
int Species_g4 = Info.EvoChainsAllGens[4].FirstOrDefault()?.Species ?? 0;
|
|
|
|
|
int Species_g5 = pkm.Format == 5 ? Info.EvoChainsAllGens[5].FirstOrDefault()?.Species ?? 0 : 0;
|
2017-05-09 03:35:06 +00:00
|
|
|
|
if (Math.Max(Species_g5, Species_g4) > Species_g3) // it has evolved in either gen 4 or gen 5; the ability must match PID
|
2017-04-14 23:24:41 +00:00
|
|
|
|
return false;
|
2017-04-12 03:11:58 +00:00
|
|
|
|
|
2017-06-21 00:57:23 +00:00
|
|
|
|
var Evolutions_g45 = Math.Max(Info.EvoChainsAllGens[4].Length, pkm.Format == 5 ? Info.EvoChainsAllGens[5].Length : 0);
|
2017-04-12 03:11:58 +00:00
|
|
|
|
if (Evolutions_g45 > 1)
|
|
|
|
|
{
|
|
|
|
|
// Evolutions_g45 > 1 and Species_g45 = Species_g3 with means both options, evolve in gen 4-5 or not evolve, are possible
|
|
|
|
|
if (pkm.Ability == abilities_g3[0])
|
|
|
|
|
// It could evolve in gen 4-5 an have generation 3 only ability
|
|
|
|
|
// that means it have not actually evolved in gen 4-5, ability do not need to match PID
|
2017-04-14 23:24:41 +00:00
|
|
|
|
return null;
|
2017-04-12 03:11:58 +00:00
|
|
|
|
if (pkm.Ability == abilities[1])
|
|
|
|
|
// It could evolve in gen4-5 an have generation 4 second ability
|
|
|
|
|
// that means it have actually evolved in gen 4-5, ability must match PID
|
2017-04-14 23:24:41 +00:00
|
|
|
|
return false;
|
2017-04-12 03:11:58 +00:00
|
|
|
|
}
|
|
|
|
|
// Evolutions_g45 == 1 means it have not evolved in gen 4-5 games,
|
|
|
|
|
// ability do not need to match PID, but only generation 3 ability is allowed
|
|
|
|
|
if (pkm.Ability != abilities_g3[0])
|
|
|
|
|
// Not evolved in gen4-5 but do not have generation 3 only ability
|
|
|
|
|
AddLine(Severity.Invalid, V373, CheckIdentifier.Ability);
|
2017-04-14 23:24:41 +00:00
|
|
|
|
return null;
|
2017-04-12 03:11:58 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyAbility5(int[] abilities)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
2017-06-03 22:16:24 +00:00
|
|
|
|
switch (EncounterMatch)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
2017-06-03 22:16:24 +00:00
|
|
|
|
case PGF g:
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyAbilityMG456(abilities, g.AbilityType);
|
2017-06-03 22:16:24 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EncounterSlot w:
|
|
|
|
|
// Hidden Abilities for Wild Encounters are only available at a Hidden Grotto
|
|
|
|
|
bool grotto = w.Type == SlotType.HiddenGrotto;
|
|
|
|
|
if (pkm.AbilityNumber == 4 ^ grotto)
|
|
|
|
|
AddLine(Severity.Invalid, grotto ? V217 : V108, CheckIdentifier.Ability);
|
|
|
|
|
break;
|
2017-09-06 01:28:38 +00:00
|
|
|
|
|
|
|
|
|
case EncounterEgg e when pkm.AbilityNumber == 4:
|
|
|
|
|
// Hidden Abilities for some are unbreedable (male only distribution)
|
2017-09-23 14:58:55 +00:00
|
|
|
|
if (Legal.MixedGenderBreeding.Contains(e.Species) || Legal.FixedGenderFromBiGender.Contains(e.Species))
|
2017-09-15 01:52:31 +00:00
|
|
|
|
break; // from female
|
2017-09-06 01:28:38 +00:00
|
|
|
|
if ((pkm.PersonalInfo.Gender & 0xFF) == 0 || Legal.Ban_BreedHidden.Contains(e.Species))
|
|
|
|
|
AddLine(Severity.Invalid, V112, CheckIdentifier.Ability);
|
|
|
|
|
break;
|
2017-04-12 03:55:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyAbility6(int[] abilities)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot slot && pkm.AbilityNumber == 4)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
bool valid = slot.Permissions.DexNav || slot.Type == SlotType.FriendSafari || slot.Type == SlotType.Horde;
|
2017-04-12 03:55:34 +00:00
|
|
|
|
if (!valid)
|
|
|
|
|
AddLine(Severity.Invalid, V300, CheckIdentifier.Ability);
|
|
|
|
|
}
|
2017-06-03 22:16:24 +00:00
|
|
|
|
else if (EncounterMatch is WC6 g)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyAbilityMG456(abilities, g.AbilityType);
|
2017-04-12 03:55:34 +00:00
|
|
|
|
else if (Legal.Ban_NoHidden6.Contains(pkm.SpecForm) && pkm.AbilityNumber == 4)
|
|
|
|
|
AddLine(Severity.Invalid, V112, CheckIdentifier.Ability);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyAbility7(int[] abilities)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot slot && pkm.AbilityNumber == 4)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
2017-05-28 04:17:53 +00:00
|
|
|
|
bool valid = slot.Type == SlotType.SOS;
|
2017-04-12 03:55:34 +00:00
|
|
|
|
if (!valid)
|
|
|
|
|
AddLine(Severity.Invalid, V111, CheckIdentifier.Ability);
|
|
|
|
|
}
|
2017-06-03 22:16:24 +00:00
|
|
|
|
else if (EncounterMatch is WC7 g)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyAbilityMG456(abilities, g.AbilityType);
|
2017-04-12 03:55:34 +00:00
|
|
|
|
else if (Legal.Ban_NoHidden7.Contains(pkm.SpecForm) && pkm.AbilityNumber == 4)
|
|
|
|
|
AddLine(Severity.Invalid, V112, CheckIdentifier.Ability);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyAbilityMG456(int[] abilities, int cardtype)
|
2017-04-12 03:55:34 +00:00
|
|
|
|
{
|
|
|
|
|
int abilNumber = pkm.AbilityNumber;
|
|
|
|
|
if (cardtype < 3 && abilNumber != 1 << cardtype) // set number
|
|
|
|
|
{
|
|
|
|
|
// Ability can be flipped 0/1 if Ability Capsule is available, is not Hidden Ability, and Abilities are different.
|
|
|
|
|
if (pkm.Format >= 6 && cardtype < 2 && abilNumber < 3 && abilities[0] != abilities[1])
|
|
|
|
|
AddLine(Severity.Valid, V109, CheckIdentifier.Ability);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V110, CheckIdentifier.Ability);
|
|
|
|
|
}
|
|
|
|
|
else if (cardtype == 3 && abilNumber == 4) // 1/2 only
|
|
|
|
|
AddLine(Severity.Invalid, V110, CheckIdentifier.Ability);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
#region VerifyBall
|
2017-09-30 21:08:35 +00:00
|
|
|
|
private void VerifyBallEquals(int ball) => AddBallLine(ball == pkm.Ball);
|
|
|
|
|
private void VerifyBallEquals(ICollection<int> balls) => AddBallLine(balls.Contains(pkm.Ball));
|
|
|
|
|
private void AddBallLine(bool valid)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{
|
2017-09-30 21:08:35 +00:00
|
|
|
|
if (valid)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V119, CheckIdentifier.Ball);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V118, CheckIdentifier.Ball);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyBall()
|
2016-03-21 15:01:08 +00:00
|
|
|
|
{
|
2017-02-28 04:57:24 +00:00
|
|
|
|
if (pkm.Format < 3)
|
|
|
|
|
return; // no ball info saved
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2016-03-23 02:47:13 +00:00
|
|
|
|
if (!Encounter.Valid)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2017-05-28 05:40:21 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift g)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-05-28 05:40:21 +00:00
|
|
|
|
if (pkm.Species == 490 && g.Ball == 0)
|
2017-03-30 18:58:30 +00:00
|
|
|
|
// there is no ball data in Manaphy Mystery Gift
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Pokeball
|
2017-03-30 18:58:30 +00:00
|
|
|
|
else
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(g.Ball);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-05-28 05:40:21 +00:00
|
|
|
|
if (EncounterMatch is EncounterLink l)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(l.Ball);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-06-03 22:16:24 +00:00
|
|
|
|
if (EncounterMatch is EncounterTrade t)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(t.Ball); // Pokeball
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-13 19:12:55 +00:00
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (pkm.Species == 292 && Info.Generation > 3) // Shedinja. For gen3, copy the ball from Nincada
|
2017-04-04 03:02:40 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Pokeball Only
|
2017-04-04 03:02:40 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-12 00:26:22 +00:00
|
|
|
|
if (pkm.Ball == 0x14 && !Info.EncounterMatch.EggEncounter && pkm.SM) // Heavy Ball
|
2017-03-13 19:12:55 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var lineage = Legal.GetLineage(pkm);
|
2017-03-14 01:38:56 +00:00
|
|
|
|
if (lineage.Any(e => Legal.AlolanCaptureNoHeavyBall.Contains(e)))
|
2017-03-15 04:13:39 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V116, CheckIdentifier.Ball);
|
2017-03-15 04:13:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-13 19:12:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch is EncounterStatic s)
|
2016-04-21 03:46:18 +00:00
|
|
|
|
{
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (s.Gift)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(s.Ball);
|
2017-12-19 00:17:21 +00:00
|
|
|
|
else if (s.Location == 75 && s.Generation == 5) // Entree Forest (Dream World)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(Legal.DreamWorldBalls);
|
2016-11-08 16:43:57 +00:00
|
|
|
|
else
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(Legal.GetWildBalls(pkm));
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot w)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-12-19 00:17:21 +00:00
|
|
|
|
if (w.Location == 30016 && w.Generation == 7) // Poké Pelago
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Pokeball
|
2017-07-07 05:05:54 +00:00
|
|
|
|
// For gen3/4 Safari Zones and BCC getValidWildEncounters already filter to not return
|
2017-03-30 11:18:05 +00:00
|
|
|
|
// 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
|
2018-03-11 03:51:09 +00:00
|
|
|
|
else if (3 <= Info.Generation && Info.Generation <= 4 && EncounterSlotGenerator.IsSafariSlot(w.Type))
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(5); // Safari Ball
|
2017-09-04 02:51:29 +00:00
|
|
|
|
else if (Info.Generation == 4 && w.Type == SlotType.BugContest)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(0x18); // Sport Ball
|
2016-11-08 16:43:57 +00:00
|
|
|
|
else
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(Legal.GetWildBalls(pkm));
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pkm.WasEgg)
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEgg();
|
2017-02-23 05:19:29 +00:00
|
|
|
|
return;
|
2016-11-11 05:10:28 +00:00
|
|
|
|
}
|
2016-03-28 05:05:51 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Pokeball
|
2016-11-11 05:10:28 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyBallEgg()
|
2017-02-23 05:19:29 +00:00
|
|
|
|
{
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Info.Generation < 6) // No inheriting Balls
|
2017-02-23 05:19:29 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Must be Pokéball -- no ball inheritance.
|
2017-02-23 05:19:29 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pkm.Ball == 0x01) // Master Ball
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{ AddLine(Severity.Invalid, V117, CheckIdentifier.Ball); return; }
|
2017-02-23 05:19:29 +00:00
|
|
|
|
if (pkm.Ball == 0x10) // Cherish Ball
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{ AddLine(Severity.Invalid, V120, CheckIdentifier.Ball); return; }
|
2017-02-23 05:19:29 +00:00
|
|
|
|
if (pkm.Ball == 0x04) // Poké Ball
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{ AddLine(Severity.Valid, V119, CheckIdentifier.Ball); return; }
|
2017-02-23 05:19:29 +00:00
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
switch (Info.Generation)
|
2017-02-23 05:19:29 +00:00
|
|
|
|
{
|
|
|
|
|
case 6: // Gen6 Inheritance Rules
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEggGen6();
|
2017-02-23 05:19:29 +00:00
|
|
|
|
return;
|
|
|
|
|
case 7: // Gen7 Inheritance Rules
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEggGen7();
|
2017-02-23 05:19:29 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyBallEggGen6()
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.Gender == 2) // Genderless
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Must be Pokéball as ball can only pass via mother (not Ditto!)
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (Legal.BreedMaleOnly.Contains(pkm.Species))
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4); // Must be Pokéball as ball can only pass via mother (not Ditto!)
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
int ball = pkm.Ball;
|
|
|
|
|
|
|
|
|
|
if (ball >= 26)
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V126, CheckIdentifier.Ball);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ball == 0x05) // Safari Ball
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (Legal.GetLineage(pkm).All(e => !Legal.Inherit_Safari.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else if (pkm.AbilityNumber == 4)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (0x10 < ball && ball < 0x18) // Apricorn Ball
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (Legal.GetLineage(pkm).All(e => !Legal.Inherit_Apricorn6.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-03-22 04:31:06 +00:00
|
|
|
|
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (ball == 0x18) // Sport Ball
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (Legal.GetLineage(pkm).All(e => !Legal.Inherit_Sport.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else if (pkm.AbilityNumber == 4)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-03-23 02:47:13 +00:00
|
|
|
|
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (ball == 0x19) // Dream Ball
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (Legal.GetLineage(pkm).Any(e => Legal.Inherit_Dream.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2016-11-26 01:54:32 +00:00
|
|
|
|
if (pkm.AbilityNumber == 4 && Legal.Ban_DreamHidden.Contains(pkm.Species))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
2016-11-26 01:54:32 +00:00
|
|
|
|
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (0x0D <= ball && ball <= 0x0F)
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (!Legal.Ban_Gen4Ball_6.Contains(pkm.Species))
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
|
|
|
|
|
return;
|
2016-03-29 05:30:23 +00:00
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked.
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
|
|
|
|
if (Legal.Ban_Gen3Ball.Contains(pkm.Species))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2017-04-02 13:39:39 +00:00
|
|
|
|
else if (pkm.AbilityNumber == 4 && Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-03-21 15:01:08 +00:00
|
|
|
|
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pkm.Species > 650 && pkm.Species != 700) // Sylveon
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (Legal.GetWildBalls(pkm).Contains(pkm.Ball))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-12 14:52:40 +00:00
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V125, CheckIdentifier.Ball);
|
2016-03-21 15:01:08 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyBallEggGen7()
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var Lineage = Legal.GetLineage(pkm).ToArray();
|
2016-12-02 02:48:38 +00:00
|
|
|
|
if (722 <= pkm.Species && pkm.Species <= 730) // G7 Starters
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(4);
|
2016-12-02 02:48:38 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
int ball = pkm.Ball;
|
|
|
|
|
if (ball == 0x05) // Safari Ball
|
2016-11-12 05:23:33 +00:00
|
|
|
|
{
|
2017-04-04 03:02:40 +00:00
|
|
|
|
if (!Lineage.Any(e => Legal.Inherit_Safari.Contains(e) || Legal.Inherit_SafariMale.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2017-04-04 03:02:40 +00:00
|
|
|
|
else if (pkm.AbilityNumber == 4 && Lineage.Any(e => Legal.Ban_SafariBallHidden_7.Contains(e)))
|
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (0x10 < ball && ball < 0x18) // Apricorn Ball
|
2016-11-12 05:23:33 +00:00
|
|
|
|
{
|
2017-04-04 03:02:40 +00:00
|
|
|
|
if (!Lineage.Any(e => Legal.Inherit_Apricorn7.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2018-03-16 02:04:14 +00:00
|
|
|
|
else if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden7Apricorn.Contains(Lineage.Last() | pkm.AltForm << 11)) // lineage is 3->2->origin
|
2017-04-04 03:02:40 +00:00
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (ball == 0x18) // Sport Ball
|
2016-11-12 05:23:33 +00:00
|
|
|
|
{
|
2017-04-04 03:02:40 +00:00
|
|
|
|
if (!Lineage.Any(e => Legal.Inherit_Sport.Contains(e)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2017-04-04 03:02:40 +00:00
|
|
|
|
else if (pkm.AbilityNumber == 4 && (Lineage.Contains(313) || Lineage.Contains(314))) // Volbeat/Illumise
|
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (ball == 0x19) // Dream Ball
|
2016-11-12 05:23:33 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (Lineage.Any(e => Legal.Inherit_Dream.Contains(e) || Legal.Inherit_DreamMale.Contains(e)))
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (0x0D <= ball && ball <= 0x0F) // Dusk Heal Quick
|
2016-11-12 05:23:33 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (!Legal.Ban_Gen4Ball_7.Contains(pkm.Species))
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (0x02 <= ball && ball <= 0x0C) // Don't worry, Ball # 0x05 was already checked.
|
2016-11-12 05:23:33 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (!Legal.Ban_Gen3Ball_7.Contains(pkm.Species))
|
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V121, CheckIdentifier.Ball);
|
2016-11-12 05:23:33 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-12 14:52:40 +00:00
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (ball == 26)
|
2016-11-12 14:52:40 +00:00
|
|
|
|
{
|
2018-02-25 01:28:07 +00:00
|
|
|
|
if (Lineage[0] == 669 && pkm.AltForm == 3 && pkm.AbilityNumber == 4)
|
|
|
|
|
{
|
|
|
|
|
// Can't obtain Flabébé-Blue with Hidden Ability in wild
|
|
|
|
|
AddLine(Severity.Invalid, V122, CheckIdentifier.Ball);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-05-10 02:27:30 +00:00
|
|
|
|
if ((pkm.Species > 731 && pkm.Species <= 785) || Lineage.Any(e => Legal.PastGenAlolanNatives.Contains(e) && !Legal.PastGenAlolanNativesUncapturable.Contains(e)))
|
2016-11-12 14:52:40 +00:00
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 14:52:40 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (Lineage.Any(e => Legal.PastGenAlolanScans.Contains(e)))
|
|
|
|
|
{
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, V123, CheckIdentifier.Ball);
|
2016-11-12 14:52:40 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// next statement catches all new alolans
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pkm.Species > 721)
|
2016-11-11 05:10:28 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyBallEquals(Legal.GetWildBalls(pkm));
|
2016-11-11 05:10:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-12 14:52:40 +00:00
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
if (ball >= 27)
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V126, CheckIdentifier.Ball);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
AddLine(Severity.Invalid, V125, CheckIdentifier.Ball);
|
2016-11-11 05:10:28 +00:00
|
|
|
|
}
|
2017-04-07 00:41:25 +00:00
|
|
|
|
#endregion
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private CheckResult VerifyHistory()
|
2016-03-22 04:31:06 +00:00
|
|
|
|
{
|
2016-03-23 02:47:13 +00:00
|
|
|
|
if (!Encounter.Valid)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Valid, V127, CheckIdentifier.History);
|
2016-12-08 02:28:24 +00:00
|
|
|
|
|
2018-03-28 23:07:03 +00:00
|
|
|
|
// ORAS contests mistakenly apply 20 affection to the OT instead of the current handler's value
|
|
|
|
|
bool IsInvalidContestAffection() => pkm.OT_Affection != 255 && pkm.OT_Affection % 20 != 0;
|
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Info.Generation < 6)
|
2016-12-08 02:28:24 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.Format < 6)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Valid, V128, CheckIdentifier.History);
|
2016-12-08 02:28:24 +00:00
|
|
|
|
|
2018-04-15 04:36:11 +00:00
|
|
|
|
if (pkm.OT_Affection != 0 && Info.Generation <= 2 || IsInvalidContestAffection())
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V129, CheckIdentifier.History);
|
2016-12-08 02:28:24 +00:00
|
|
|
|
if (pkm.OT_Memory > 0 || pkm.OT_Feeling > 0 || pkm.OT_Intensity > 0 || pkm.OT_TextVar > 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V130, CheckIdentifier.History);
|
2016-12-08 02:28:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (pkm.Format >= 6 && Info.Generation != pkm.Format && pkm.CurrentHandler != 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V124, CheckIdentifier.History);
|
2017-02-07 06:19:10 +00:00
|
|
|
|
|
2016-12-08 02:28:24 +00:00
|
|
|
|
if (pkm.HT_Gender > 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V131, pkm.HT_Gender), CheckIdentifier.History);
|
2017-01-25 17:17:20 +00:00
|
|
|
|
|
2017-11-18 19:34:23 +00:00
|
|
|
|
if (EncounterMatch is WC6 wc6 && wc6.OT_Name.Length > 0)
|
2016-03-22 04:31:06 +00:00
|
|
|
|
{
|
2017-09-05 01:55:15 +00:00
|
|
|
|
if (pkm.OT_Friendship != PersonalTable.AO[EncounterMatch.Species].BaseFriendship)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V132, CheckIdentifier.History);
|
2018-03-28 23:07:03 +00:00
|
|
|
|
if (pkm.OT_Affection != 0 && (pkm.AO || !pkm.IsUntraded) && IsInvalidContestAffection())
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V133, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.CurrentHandler != 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V134, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
}
|
2018-02-08 03:56:02 +00:00
|
|
|
|
else if (EncounterMatch is WC7 wc7 && wc7.OT_Name.Length > 0 && wc7.TID != 18075) // Ash Pikachu QR Gift doesn't set Current Handler
|
2017-01-11 01:14:48 +00:00
|
|
|
|
{
|
2017-09-19 05:36:06 +00:00
|
|
|
|
if (pkm.OT_Friendship != PersonalTable.USUM[EncounterMatch.Species].BaseFriendship)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V132, CheckIdentifier.History);
|
2017-01-11 01:14:48 +00:00
|
|
|
|
if (pkm.OT_Affection != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V133, CheckIdentifier.History);
|
2017-01-11 01:14:48 +00:00
|
|
|
|
if (pkm.CurrentHandler != 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V134, CheckIdentifier.History);
|
2017-01-11 01:14:48 +00:00
|
|
|
|
}
|
2017-09-05 01:55:15 +00:00
|
|
|
|
else if (EncounterMatch is MysteryGift mg && mg.Format < 6 && pkm.Format >= 6)
|
2017-01-11 01:14:48 +00:00
|
|
|
|
{
|
2018-04-14 01:52:38 +00:00
|
|
|
|
if (pkm.OT_Affection != 0 && IsInvalidContestAffection())
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V133, CheckIdentifier.History);
|
2017-01-11 01:14:48 +00:00
|
|
|
|
if (pkm.CurrentHandler != 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V134, CheckIdentifier.History);
|
2017-01-11 01:14:48 +00:00
|
|
|
|
}
|
2017-01-31 01:49:28 +00:00
|
|
|
|
|
|
|
|
|
// Geolocations
|
|
|
|
|
var geo = new[]
|
2016-11-11 03:29:00 +00:00
|
|
|
|
{
|
2017-01-31 01:49:28 +00:00
|
|
|
|
pkm.Geo1_Country, pkm.Geo2_Country, pkm.Geo3_Country, pkm.Geo4_Country, pkm.Geo5_Country,
|
|
|
|
|
pkm.Geo1_Region, pkm.Geo2_Region, pkm.Geo3_Region, pkm.Geo4_Region, pkm.Geo5_Region,
|
|
|
|
|
};
|
2017-01-27 13:59:08 +00:00
|
|
|
|
|
2017-01-31 01:49:28 +00:00
|
|
|
|
// Check sequential order (no zero gaps)
|
|
|
|
|
bool geoEnd = false;
|
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
|
{
|
|
|
|
|
if (geoEnd && geo[i] != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V135, CheckIdentifier.History);
|
2017-01-27 13:59:08 +00:00
|
|
|
|
|
2017-01-31 01:49:28 +00:00
|
|
|
|
if (geo[i] != 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (geo[i + 5] != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V136, CheckIdentifier.History);
|
2017-01-31 01:49:28 +00:00
|
|
|
|
geoEnd = true;
|
|
|
|
|
}
|
|
|
|
|
if (pkm.Format >= 7)
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return VerifyHistory7(geo);
|
2017-04-01 21:20:00 +00:00
|
|
|
|
|
|
|
|
|
// Determine if we should check for Handling Trainer Memories
|
|
|
|
|
// A Pokémon is untraded if...
|
|
|
|
|
bool untraded = pkm.HT_Name.Length == 0 || pkm.Geo1_Country == 0;
|
2017-10-06 06:13:48 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift gift)
|
2017-04-01 21:20:00 +00:00
|
|
|
|
{
|
|
|
|
|
untraded |= !pkm.WasEventEgg;
|
2017-10-06 06:13:48 +00:00
|
|
|
|
untraded &= gift.IsEgg;
|
2017-04-01 21:20:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-12 00:01:24 +00:00
|
|
|
|
if (EncounterMatch is EncounterLink link && link.OT == false)
|
2017-04-01 21:20:00 +00:00
|
|
|
|
untraded = false;
|
2017-09-04 02:51:29 +00:00
|
|
|
|
else if (Info.Generation < 6)
|
2017-04-01 21:20:00 +00:00
|
|
|
|
untraded = false;
|
|
|
|
|
|
|
|
|
|
if (untraded) // Is not Traded
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.HT_Name.Length != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V146, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.Geo1_Country != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V147, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.HT_Memory != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V148, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.CurrentHandler != 0) // Badly edited; PKHeX doesn't trip this.
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V139, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.HT_Friendship != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V140, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.HT_Affection != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V141, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.XY && pkm.CNTs.Any(stat => stat > 0))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V138, CheckIdentifier.History);
|
2016-03-22 04:31:06 +00:00
|
|
|
|
|
2017-09-05 01:55:15 +00:00
|
|
|
|
if (VerifyHistoryUntradedHandler(pkm, out CheckResult chk1))
|
|
|
|
|
return chk1;
|
|
|
|
|
if (EncounterMatch.Species != pkm.Species && VerifyHistoryUntradedEvolution(pkm, out CheckResult chk2))
|
|
|
|
|
return chk2;
|
2016-03-22 04:31:06 +00:00
|
|
|
|
}
|
|
|
|
|
else // Is Traded
|
|
|
|
|
{
|
2017-07-14 04:05:20 +00:00
|
|
|
|
if (pkm.Format == 6 && pkm.HT_Memory == 0 && !pkm.IsEgg)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V150, CheckIdentifier.History);
|
2016-03-22 04:31:06 +00:00
|
|
|
|
}
|
2016-03-31 01:53:34 +00:00
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
// Memory ChecksResult
|
|
|
|
|
if (pkm.IsEgg)
|
2016-03-31 01:53:34 +00:00
|
|
|
|
{
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.HT_Memory != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V149, CheckIdentifier.History);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.OT_Memory != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V151, CheckIdentifier.History);
|
2016-03-31 01:53:34 +00:00
|
|
|
|
}
|
2017-07-30 19:31:17 +00:00
|
|
|
|
else if (!(EncounterMatch is WC6))
|
2016-03-31 01:53:34 +00:00
|
|
|
|
{
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.OT_Memory == 0 ^ !pkm.Gen6)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V152, CheckIdentifier.History);
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Info.Generation < 6 && pkm.OT_Affection != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, V129, CheckIdentifier.History);
|
2016-03-31 01:53:34 +00:00
|
|
|
|
}
|
2016-03-22 04:31:06 +00:00
|
|
|
|
// Unimplemented: Ingame Trade Memories
|
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Valid, V145, CheckIdentifier.History);
|
2016-03-22 04:31:06 +00:00
|
|
|
|
}
|
2017-09-05 01:55:15 +00:00
|
|
|
|
private CheckResult VerifyHistory7(int[] geo)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.VC1)
|
|
|
|
|
{
|
|
|
|
|
var hasGeo = geo.Any(d => d != 0);
|
|
|
|
|
|
|
|
|
|
if (!hasGeo)
|
|
|
|
|
return new CheckResult(Severity.Invalid, V137, CheckIdentifier.History);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Info.Generation >= 7 && pkm.CNTs.Any(stat => stat > 0))
|
|
|
|
|
return new CheckResult(Severity.Invalid, V138, CheckIdentifier.History);
|
|
|
|
|
|
|
|
|
|
if (!pkm.WasEvent && pkm.HT_Name.Length == 0) // Is not Traded
|
|
|
|
|
{
|
|
|
|
|
if (VerifyHistoryUntradedHandler(pkm, out CheckResult chk1))
|
|
|
|
|
return chk1;
|
|
|
|
|
if (EncounterMatch.Species != pkm.Species && VerifyHistoryUntradedEvolution(pkm, out CheckResult chk2))
|
|
|
|
|
return chk2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new CheckResult(Severity.Valid, V145, CheckIdentifier.History);
|
|
|
|
|
}
|
|
|
|
|
private static bool VerifyHistoryUntradedHandler(PKM pkm, out CheckResult result)
|
|
|
|
|
{
|
|
|
|
|
result = null;
|
|
|
|
|
if (pkm.CurrentHandler != 0) // Badly edited; PKHeX doesn't trip this.
|
|
|
|
|
result = new CheckResult(Severity.Invalid, V139, CheckIdentifier.History);
|
|
|
|
|
else if (pkm.HT_Friendship != 0)
|
|
|
|
|
result = new CheckResult(Severity.Invalid, V140, CheckIdentifier.History);
|
|
|
|
|
else if (pkm.HT_Affection != 0)
|
|
|
|
|
result = new CheckResult(Severity.Invalid, V141, CheckIdentifier.History);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
private static bool VerifyHistoryUntradedEvolution(PKM pkm, out CheckResult result)
|
|
|
|
|
{
|
|
|
|
|
result = null;
|
|
|
|
|
// Handling Trainer string is empty implying it has not been traded.
|
|
|
|
|
// If it must be trade evolved, flag it.
|
|
|
|
|
|
|
|
|
|
if (pkm.Species == 350) // Milotic
|
|
|
|
|
{
|
2017-11-15 18:11:05 +00:00
|
|
|
|
if (Legal.IsTradeEvolved(pkm))
|
|
|
|
|
return false;
|
2017-09-05 01:55:15 +00:00
|
|
|
|
if (pkm.CNT_Beauty < 170) // Beauty Contest Stat Requirement
|
|
|
|
|
result = new CheckResult(Severity.Invalid, V143, CheckIdentifier.History);
|
|
|
|
|
else if (pkm.CurrentLevel == 1)
|
|
|
|
|
result = new CheckResult(Severity.Invalid, V144, CheckIdentifier.History);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2017-11-15 18:11:05 +00:00
|
|
|
|
return true;
|
2017-09-05 01:55:15 +00:00
|
|
|
|
}
|
2017-11-15 18:11:05 +00:00
|
|
|
|
if (!Legal.IsTradeEvolved(pkm))
|
|
|
|
|
return false;
|
|
|
|
|
result = new CheckResult(Severity.Invalid, V142, CheckIdentifier.History);
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private CheckResult VerifyCommonMemory(int handler)
|
2016-05-07 06:16:35 +00:00
|
|
|
|
{
|
|
|
|
|
int m = 0;
|
2016-05-09 23:09:40 +00:00
|
|
|
|
int t = 0;
|
2018-04-28 13:26:04 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
int f = 0;
|
2016-05-07 06:16:35 +00:00
|
|
|
|
string resultPrefix = "";
|
|
|
|
|
switch (handler)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
2016-10-23 19:48:49 +00:00
|
|
|
|
m = pkm.OT_Memory;
|
|
|
|
|
t = pkm.OT_TextVar;
|
2018-04-28 13:26:04 +00:00
|
|
|
|
i = pkm.OT_Intensity;
|
|
|
|
|
f = pkm.OT_Feeling;
|
2017-03-21 07:18:38 +00:00
|
|
|
|
resultPrefix = V205;
|
2016-05-07 06:16:35 +00:00
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2016-10-23 19:48:49 +00:00
|
|
|
|
m = pkm.HT_Memory;
|
|
|
|
|
t = pkm.HT_TextVar;
|
2018-04-28 13:26:04 +00:00
|
|
|
|
i = pkm.HT_Intensity;
|
|
|
|
|
f = pkm.HT_Feeling;
|
2017-03-21 07:18:38 +00:00
|
|
|
|
resultPrefix = V206;
|
2016-05-07 06:16:35 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
int matchingMoveMemory = Array.IndexOf(Legal.MoveSpecificMemories[0], m);
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (matchingMoveMemory != -1 && pkm.Species != 235 && !Legal.GetCanLearnMachineMove(pkm, Legal.MoveSpecificMemories[1][matchingMoveMemory], 6))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V153, resultPrefix), CheckIdentifier.Memory);
|
2017-02-21 03:40:50 +00:00
|
|
|
|
|
2016-05-09 23:09:40 +00:00
|
|
|
|
if (m == 6 && !Legal.LocationsWithPKCenter[0].Contains(t))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V154, resultPrefix), CheckIdentifier.Memory);
|
2017-02-21 03:40:50 +00:00
|
|
|
|
|
2016-05-10 01:19:31 +00:00
|
|
|
|
if (m == 21) // {0} saw {2} carrying {1} on its back. {4} that {3}.
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (!Legal.GetCanLearnMachineMove(new PK6 {Species = t, EXP = PKX.GetEXP(100, t)}, 19, 6))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V153, resultPrefix), CheckIdentifier.Memory);
|
2017-02-21 03:40:50 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if ((m == 16 || m == 48) && (t == 0 || !Legal.GetCanKnowMove(pkm, t, 6)))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V153, resultPrefix), CheckIdentifier.Memory);
|
2017-02-21 03:40:50 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
if (m == 49 && (t == 0 || !Legal.GetCanRelearnMove(pkm, t, 6))) // {0} was able to remember {2} at {1}'s instruction. {4} that {3}.
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V153, resultPrefix), CheckIdentifier.Memory);
|
2017-02-21 03:40:50 +00:00
|
|
|
|
|
2018-04-28 13:26:04 +00:00
|
|
|
|
if (i < Legal.MemoryMinIntensity[m])
|
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V254, resultPrefix, Legal.MemoryMinIntensity[m]), CheckIdentifier.Memory);
|
|
|
|
|
|
|
|
|
|
if (m != 4 && (Legal.MemoryFeelings[m] & (1 << f)) == 0)
|
|
|
|
|
return new CheckResult(Severity.Invalid, string.Format(V255, resultPrefix), CheckIdentifier.Memory);
|
|
|
|
|
|
2017-03-21 07:18:38 +00:00
|
|
|
|
return new CheckResult(Severity.Valid, string.Format(V155, resultPrefix), CheckIdentifier.Memory);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyOTMemoryIs(int[] values)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.OT_Memory != values[0])
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V197, V205, values[0]), CheckIdentifier.Memory);
|
|
|
|
|
if (pkm.OT_Intensity != values[1])
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V198, V205, values[1]), CheckIdentifier.Memory);
|
|
|
|
|
if (pkm.OT_TextVar != values[2])
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V199, V205, values[2]), CheckIdentifier.Memory);
|
|
|
|
|
if (pkm.OT_Feeling != values[3])
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V200, V205, values[3]), CheckIdentifier.Memory);
|
2016-05-07 06:16:35 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyOTMemory()
|
2016-05-06 03:05:22 +00:00
|
|
|
|
{
|
2016-11-26 01:30:39 +00:00
|
|
|
|
if (pkm.Format < 6)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-11-26 01:30:39 +00:00
|
|
|
|
|
|
|
|
|
if (!History.Valid)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-05-06 03:05:22 +00:00
|
|
|
|
|
2018-04-28 13:26:04 +00:00
|
|
|
|
if (Info.Generation < 6 || pkm.IsEgg)
|
2016-05-06 03:05:22 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyOTMemoryIs(new [] {0, 0, 0, 0}); // empty
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-05-06 03:05:22 +00:00
|
|
|
|
}
|
2016-11-26 01:30:39 +00:00
|
|
|
|
|
2017-10-06 06:13:48 +00:00
|
|
|
|
switch (EncounterMatch)
|
2016-11-26 01:30:39 +00:00
|
|
|
|
{
|
2017-10-06 06:13:48 +00:00
|
|
|
|
case EncounterTrade _:
|
|
|
|
|
switch (Info.Generation)
|
|
|
|
|
{
|
|
|
|
|
case 6:
|
|
|
|
|
break; // Undocumented, uncommon, and insignificant -- don't bother.
|
|
|
|
|
case 7:
|
|
|
|
|
VerifyOTMemoryIs(new[] { 1, 3, 40, 5 });
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case WC6 g when !g.IsEgg:
|
|
|
|
|
VerifyOTMemoryIs(new[] { g.OT_Memory, g.OT_Intensity, g.OT_TextVar, g.OT_Feeling });
|
|
|
|
|
return;
|
|
|
|
|
case WC7 g when !g.IsEgg:
|
|
|
|
|
VerifyOTMemoryIs(new[] { g.OT_Memory, g.OT_Intensity, g.OT_TextVar, g.OT_Feeling });
|
|
|
|
|
return;
|
2016-11-26 01:30:39 +00:00
|
|
|
|
}
|
2017-10-06 06:13:48 +00:00
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Info.Generation >= 7)
|
2016-11-26 01:30:39 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyOTMemoryIs(new[] {0, 0, 0, 0}); // empty
|
2016-11-26 01:30:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
switch (pkm.OT_Memory)
|
2016-05-06 03:05:22 +00:00
|
|
|
|
{
|
2016-05-25 05:20:19 +00:00
|
|
|
|
case 2: // {0} hatched from an Egg and saw {1} for the first time at... {2}. {4} that {3}.
|
2017-10-06 06:13:48 +00:00
|
|
|
|
if (pkm.Egg_Location == 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V160, V205), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2016-05-06 03:05:22 +00:00
|
|
|
|
case 4: // {0} became {1}’s friend when it arrived via Link Trade at... {2}. {4} that {3}.
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V161, V205), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2016-05-09 23:09:40 +00:00
|
|
|
|
case 6: // {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}.
|
2016-10-23 19:48:49 +00:00
|
|
|
|
int matchingOriginGame = Array.IndexOf(Legal.LocationsWithPKCenter[0], pkm.OT_TextVar);
|
2016-05-10 00:51:35 +00:00
|
|
|
|
if (matchingOriginGame != -1)
|
|
|
|
|
{
|
|
|
|
|
int gameID = Legal.LocationsWithPKCenter[1][matchingOriginGame];
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.XY && gameID != 0 || pkm.AO && gameID != 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V162, V205), CheckIdentifier.Memory);
|
2016-05-10 00:51:35 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
AddLine(VerifyCommonMemory(0));
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2016-05-06 03:35:18 +00:00
|
|
|
|
case 14:
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (!Legal.GetCanBeCaptured(pkm.OT_TextVar, Info.Generation, (GameVersion)pkm.Version))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V165, V205), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, string.Format(V164, V205), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-05-06 03:05:22 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.XY && Legal.Memory_NotXY.Contains(pkm.OT_Memory))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V163, V205), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.AO && Legal.Memory_NotAO.Contains(pkm.OT_Memory))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V163, V205), CheckIdentifier.Memory);
|
2016-05-06 03:05:22 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
AddLine(VerifyCommonMemory(0));
|
2016-05-06 03:05:22 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyHTMemory()
|
2016-05-06 03:05:22 +00:00
|
|
|
|
{
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.Format < 6)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-05-06 03:05:22 +00:00
|
|
|
|
if (!History.Valid)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-05-06 03:05:22 +00:00
|
|
|
|
|
2017-03-12 23:36:23 +00:00
|
|
|
|
if (pkm.Format >= 7)
|
2016-11-26 01:30:39 +00:00
|
|
|
|
{
|
2017-03-12 23:36:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Bank Transfer adds in the Link Trade Memory.
|
|
|
|
|
* Trading 7<->7 between games (not Bank) clears this data.
|
|
|
|
|
*/
|
|
|
|
|
if (pkm.HT_Memory == 0)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.HT_TextVar != 0 || pkm.HT_Intensity != 0 || pkm.HT_Feeling != 0)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V329, CheckIdentifier.Memory);
|
2017-01-27 13:59:08 +00:00
|
|
|
|
return;
|
2017-03-12 23:36:23 +00:00
|
|
|
|
}
|
2017-01-27 04:13:27 +00:00
|
|
|
|
|
2017-05-19 00:38:26 +00:00
|
|
|
|
// Transfer 6->7 & withdraw to same HT => keeps past gen memory
|
|
|
|
|
// Don't require link trade memory for these past gen cases
|
2017-09-04 02:51:29 +00:00
|
|
|
|
int gen = Info.Generation;
|
2017-05-19 00:38:26 +00:00
|
|
|
|
if (3 <= gen && gen < 7 && pkm.CurrentHandler == 1)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-01-27 13:59:08 +00:00
|
|
|
|
if (pkm.HT_Memory != 4)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V156, CheckIdentifier.Memory);
|
2017-01-27 05:35:26 +00:00
|
|
|
|
if (pkm.HT_TextVar != 0)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V157, CheckIdentifier.Memory);
|
2017-01-27 13:59:08 +00:00
|
|
|
|
if (pkm.HT_Intensity != 1)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V158, CheckIdentifier.Memory);
|
2017-01-27 13:59:08 +00:00
|
|
|
|
if (pkm.HT_Feeling > 10)
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V159, CheckIdentifier.Memory);
|
2016-11-26 01:30:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
switch (pkm.HT_Memory)
|
2016-05-06 03:05:22 +00:00
|
|
|
|
{
|
2017-01-27 04:13:27 +00:00
|
|
|
|
case 0:
|
2017-01-27 13:59:08 +00:00
|
|
|
|
if (string.IsNullOrEmpty(pkm.HT_Name))
|
2017-01-27 04:13:27 +00:00
|
|
|
|
return;
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, V150, CheckIdentifier.Memory); return;
|
2016-05-06 03:05:22 +00:00
|
|
|
|
case 1: // {0} met {1} at... {2}. {1} threw a Poké Ball at it, and they started to travel together. {4} that {3}.
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V202, V206), CheckIdentifier.Memory); return;
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2016-05-06 03:05:22 +00:00
|
|
|
|
case 2: // {0} hatched from an Egg and saw {1} for the first time at... {2}. {4} that {3}.
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V160, V206), CheckIdentifier.Memory); return;
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2016-05-06 03:35:18 +00:00
|
|
|
|
case 14:
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (Legal.GetCanBeCaptured(pkm.HT_TextVar, Info.Generation))
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Valid, string.Format(V164, V206), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-03-21 07:18:38 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V165, V206), CheckIdentifier.Memory);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-05-06 03:05:22 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
AddLine(VerifyCommonMemory(1));
|
2016-05-06 03:05:22 +00:00
|
|
|
|
}
|
2017-09-05 01:55:15 +00:00
|
|
|
|
private void VerifyConsoleRegion()
|
2016-05-11 23:20:31 +00:00
|
|
|
|
{
|
2017-09-05 01:55:15 +00:00
|
|
|
|
AddLine(VerifyConsoleRegion(pkm));
|
|
|
|
|
}
|
|
|
|
|
private static CheckResult VerifyConsoleRegion(PKM pkm)
|
|
|
|
|
{
|
|
|
|
|
int consoleRegion = pkm.ConsoleRegion;
|
|
|
|
|
if (consoleRegion >= 7)
|
|
|
|
|
return new CheckResult(Severity.Invalid, V301, CheckIdentifier.Geography);
|
|
|
|
|
return IsConsoleRegionCountryValid(consoleRegion, pkm.Country)
|
|
|
|
|
? new CheckResult(Severity.Valid, V303, CheckIdentifier.Geography)
|
|
|
|
|
: new CheckResult(Severity.Invalid, V302, CheckIdentifier.Geography);
|
|
|
|
|
}
|
|
|
|
|
private static bool IsConsoleRegionCountryValid(int consoleRegion, int country)
|
|
|
|
|
{
|
|
|
|
|
switch (consoleRegion)
|
2016-05-11 23:20:31 +00:00
|
|
|
|
{
|
2016-05-12 04:18:05 +00:00
|
|
|
|
case 0: // Japan
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return country == 1;
|
2016-05-12 04:18:05 +00:00
|
|
|
|
case 1: // Americas
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return 8 <= country && country <= 52 || new[] {153, 156, 168, 174, 186}.Contains(country);
|
2016-05-12 04:18:05 +00:00
|
|
|
|
case 2: // Europe
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return 64 <= country && country <= 127 || new[] {169, 184, 185}.Contains(country);
|
2016-05-12 04:18:05 +00:00
|
|
|
|
case 4: // China
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return country == 144 || country == 160;
|
2016-05-12 04:18:05 +00:00
|
|
|
|
case 5: // Korea
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return country == 136;
|
2016-05-12 04:18:05 +00:00
|
|
|
|
case 6: // Taiwan
|
2017-09-20 22:18:33 +00:00
|
|
|
|
return country == 144 || country == 128;
|
2016-10-23 19:48:49 +00:00
|
|
|
|
default:
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return false;
|
2016-05-11 23:20:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyForm()
|
2016-04-14 10:17:03 +00:00
|
|
|
|
{
|
|
|
|
|
if (!Encounter.Valid)
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
2016-04-14 10:17:03 +00:00
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.Format < 4)
|
2017-08-01 21:55:10 +00:00
|
|
|
|
return; // no forms exist
|
|
|
|
|
|
2017-11-07 03:31:24 +00:00
|
|
|
|
int count = PersonalInfo.FormeCount;
|
2017-11-07 05:08:39 +00:00
|
|
|
|
if (count <= 1 && pkm.AltForm == 0)
|
2017-08-01 21:55:10 +00:00
|
|
|
|
return; // no forms to check
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
2017-11-22 02:31:24 +00:00
|
|
|
|
if (!PersonalInfo.IsFormeWithinRange(pkm.AltForm) && !FormConverter.IsValidOutOfBoundsForme(pkm.Species, pkm.AltForm, Info.Generation))
|
2016-11-09 05:43:22 +00:00
|
|
|
|
{
|
2017-11-16 22:30:18 +00:00
|
|
|
|
AddLine(Severity.Invalid, string.Format(V304, count-1, pkm.AltForm), CheckIdentifier.Form);
|
2017-09-05 01:55:15 +00:00
|
|
|
|
return;
|
2016-11-09 05:43:22 +00:00
|
|
|
|
}
|
2017-09-05 01:55:15 +00:00
|
|
|
|
|
2017-05-28 04:17:53 +00:00
|
|
|
|
if (EncounterMatch is EncounterSlot w && w.Type == SlotType.FriendSafari)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyFormFriendSafari();
|
2017-11-28 02:13:54 +00:00
|
|
|
|
else if (EncounterMatch is EncounterEgg)
|
|
|
|
|
{
|
|
|
|
|
if (FormConverter.IsTotemForm(pkm.Species, pkm.AltForm))
|
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, V317, CheckIdentifier.Form);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-09 05:43:22 +00:00
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
switch (pkm.Species)
|
2016-04-14 10:17:03 +00:00
|
|
|
|
{
|
2018-01-18 21:50:29 +00:00
|
|
|
|
case 25 when Info.Generation == 6: // Pikachu Cosplay
|
|
|
|
|
if (pkm.AltForm != 0 ^ Type == typeof(EncounterStatic))
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2017-04-24 00:53:22 +00:00
|
|
|
|
string msg = Type == typeof(EncounterStatic) ? V305 : V306;
|
2017-02-21 03:40:50 +00:00
|
|
|
|
AddLine(Severity.Invalid, msg, CheckIdentifier.Form);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-01-18 21:50:29 +00:00
|
|
|
|
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())
|
2016-10-23 19:48:49 +00:00
|
|
|
|
{
|
2018-01-16 01:50:33 +00:00
|
|
|
|
bool gift = EncounterMatch is WC7 g && g.Form != pkm.AltForm;
|
|
|
|
|
var msg = gift ? V307 : V317;
|
|
|
|
|
AddLine(Severity.Invalid, msg, CheckIdentifier.Form);
|
|
|
|
|
return;
|
2016-10-23 19:48:49 +00:00
|
|
|
|
}
|
2016-04-23 21:16:12 +00:00
|
|
|
|
break;
|
2017-11-07 01:13:16 +00:00
|
|
|
|
case 201 when Info.Generation == 2 && pkm.AltForm >= 26:
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V304, "Z", pkm.AltForm == 26 ? "!" : "?"), CheckIdentifier.Form);
|
|
|
|
|
break;
|
2017-01-31 22:01:32 +00:00
|
|
|
|
case 487: // Giratina
|
2017-02-03 03:30:17 +00:00
|
|
|
|
if (pkm.AltForm == 1 ^ pkm.HeldItem == 112) // Origin form only with Griseous Orb
|
2017-01-31 22:01:32 +00:00
|
|
|
|
{
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V308, CheckIdentifier.Form);
|
2017-01-31 22:01:32 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2017-02-01 04:11:11 +00:00
|
|
|
|
case 493: // Arceus
|
|
|
|
|
{
|
|
|
|
|
int item = pkm.HeldItem;
|
|
|
|
|
int form = 0;
|
2017-09-05 01:55:15 +00:00
|
|
|
|
if (298 <= item && item <= 313 || item == 644)
|
2017-02-01 04:11:11 +00:00
|
|
|
|
form = Array.IndexOf(Legal.Arceus_Plate, item) + 1;
|
|
|
|
|
else if (777 <= item && item <= 793)
|
|
|
|
|
form = Array.IndexOf(Legal.Arceus_ZCrystal, item) + 1;
|
2018-04-15 01:20:58 +00:00
|
|
|
|
if (pkm.Format == 4 && form >= 9)
|
|
|
|
|
form++; // ??? type Form shifts everything by 1
|
2017-09-05 01:55:15 +00:00
|
|
|
|
|
2017-02-01 04:11:11 +00:00
|
|
|
|
if (form != pkm.AltForm)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V308, CheckIdentifier.Form);
|
2017-02-01 04:11:11 +00:00
|
|
|
|
else if (form != 0)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Valid, V309, CheckIdentifier.Form);
|
2017-02-01 04:11:11 +00:00
|
|
|
|
}
|
2017-02-13 01:06:09 +00:00
|
|
|
|
break;
|
2017-03-23 06:34:35 +00:00
|
|
|
|
case 647: // Keldeo
|
|
|
|
|
{
|
2017-11-27 06:19:18 +00:00
|
|
|
|
if (pkm.Gen5) // can mismatch in gen5 via BW tutor and transfer up
|
2017-07-26 03:39:54 +00:00
|
|
|
|
break;
|
2017-03-23 06:34:35 +00:00
|
|
|
|
int index = Array.IndexOf(pkm.Moves, 548); // Secret Sword
|
|
|
|
|
bool noSword = index < 0;
|
|
|
|
|
if (pkm.AltForm == 0 ^ noSword) // mismatch
|
2017-06-21 00:57:23 +00:00
|
|
|
|
Info.Moves[noSword ? 0 : index] = new CheckMoveResult(Info.Moves[noSword ? 0 : index], Severity.Invalid, V169, CheckIdentifier.Move);
|
2017-03-23 06:34:35 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-02-13 01:06:09 +00:00
|
|
|
|
case 649: // Genesect
|
|
|
|
|
{
|
|
|
|
|
int item = pkm.HeldItem;
|
|
|
|
|
int form = 0;
|
|
|
|
|
if (116 <= item && item <= 119)
|
|
|
|
|
form = item - 115;
|
|
|
|
|
|
|
|
|
|
if (form != pkm.AltForm)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V308, CheckIdentifier.Form);
|
2017-02-13 01:06:09 +00:00
|
|
|
|
else
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Valid, V309, CheckIdentifier.Form);
|
2017-02-13 01:06:09 +00:00
|
|
|
|
}
|
2017-02-01 04:11:11 +00:00
|
|
|
|
break;
|
2016-11-14 02:25:33 +00:00
|
|
|
|
case 658: // Greninja
|
2016-11-09 05:43:22 +00:00
|
|
|
|
if (pkm.AltForm > 1) // Ash Battle Bond active
|
|
|
|
|
{
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V310, CheckIdentifier.Form);
|
2017-07-14 04:12:16 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-30 15:14:42 +00:00
|
|
|
|
if (pkm.AltForm != 0 && Type != typeof(MysteryGift)) // Formes are not breedable, MysteryGift already checked
|
2017-07-14 04:12:16 +00:00
|
|
|
|
{
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V304, 0, pkm.AltForm), CheckIdentifier.Form);
|
2016-11-09 05:43:22 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-11-14 02:25:33 +00:00
|
|
|
|
case 664: // Scatterbug
|
|
|
|
|
case 665: // Spewpa
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.AltForm > 17) // Fancy & Pokéball
|
|
|
|
|
{
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V311, CheckIdentifier.Form);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region))
|
|
|
|
|
AddLine(Severity.Fishy, V312, CheckIdentifier.Form);
|
2016-04-14 10:17:03 +00:00
|
|
|
|
break;
|
2016-11-14 02:25:33 +00:00
|
|
|
|
case 666: // Vivillon
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.AltForm > 17) // Fancy & Pokéball
|
|
|
|
|
{
|
2017-04-24 00:53:22 +00:00
|
|
|
|
if (Type != typeof(MysteryGift))
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V312, CheckIdentifier.Form);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Valid, V313, CheckIdentifier.Form);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-03-25 17:24:56 +00:00
|
|
|
|
if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region))
|
|
|
|
|
AddLine(Severity.Fishy, V312, CheckIdentifier.Form);
|
2016-04-14 10:17:03 +00:00
|
|
|
|
break;
|
2016-11-14 02:25:33 +00:00
|
|
|
|
case 670: // Floette
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.AltForm == 5) // Eternal Flower -- Never Released
|
|
|
|
|
{
|
2017-04-24 00:53:22 +00:00
|
|
|
|
if (Type != typeof(MysteryGift))
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V314, CheckIdentifier.Form);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
else
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Valid, V315, CheckIdentifier.Form);
|
2016-10-23 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-04-14 10:17:03 +00:00
|
|
|
|
break;
|
2017-02-01 04:11:11 +00:00
|
|
|
|
case 773: // Silvally
|
|
|
|
|
{
|
|
|
|
|
int item = pkm.HeldItem;
|
|
|
|
|
int form = 0;
|
|
|
|
|
if ((904 <= item && item <= 920) || item == 644)
|
|
|
|
|
form = item - 903;
|
|
|
|
|
if (form != pkm.AltForm)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V308, CheckIdentifier.Form);
|
2017-02-01 04:11:11 +00:00
|
|
|
|
else if (form != 0)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Valid, V309, CheckIdentifier.Form);
|
2017-02-01 04:11:11 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-02-03 03:27:48 +00:00
|
|
|
|
|
2017-11-16 00:28:47 +00:00
|
|
|
|
case 744 when Info.EncounterMatch.EggEncounter && pkm.AltForm == 1 && pkm.SM:
|
|
|
|
|
case 745 when Info.EncounterMatch.EggEncounter && pkm.AltForm == 2 && pkm.SM:
|
|
|
|
|
AddLine(Severity.Invalid, V317, CheckIdentifier.Form);
|
|
|
|
|
return;
|
|
|
|
|
|
2017-02-03 03:27:48 +00:00
|
|
|
|
// Party Only Forms
|
|
|
|
|
case 492: // Shaymin
|
|
|
|
|
case 676: // Furfrou
|
|
|
|
|
case 720: // Hoopa
|
2017-04-15 00:49:13 +00:00
|
|
|
|
if (pkm.AltForm != 0 && pkm.Box > -1 && pkm.Format <= 6) // has form but stored in box
|
2017-02-03 03:30:17 +00:00
|
|
|
|
{
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V316, CheckIdentifier.Form);
|
2017-02-03 03:30:17 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-02-03 03:27:48 +00:00
|
|
|
|
break;
|
2017-11-09 00:27:35 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
AddLine(Severity.Invalid, V310, CheckIdentifier.Form);
|
|
|
|
|
return;
|
2017-11-10 17:22:41 +00:00
|
|
|
|
case 800 when pkm.AltForm < 3: // Necrozma Fused forms & default
|
2017-11-10 03:26:47 +00:00
|
|
|
|
case 778 when pkm.AltForm == 2: // Totem disguise Mimikyu
|
|
|
|
|
AddLine(Severity.Valid, V315, CheckIdentifier.Form);
|
|
|
|
|
return;
|
2016-04-14 10:17:03 +00:00
|
|
|
|
}
|
2016-11-14 02:19:09 +00:00
|
|
|
|
|
2017-09-04 02:51:29 +00:00
|
|
|
|
if (pkm.Format >= 7 && Info.Generation < 7 && pkm.AltForm != 0)
|
2017-02-02 05:59:39 +00:00
|
|
|
|
{
|
2018-04-07 04:46:27 +00:00
|
|
|
|
if (pkm.Species == 25 || Legal.AlolanOriginForms.Contains(pkm.Species)
|
2018-04-14 01:44:16 +00:00
|
|
|
|
|| Legal.AlolanVariantEvolutions12.Contains((EncounterOriginalGB ?? EncounterMatch).Species))
|
2017-03-23 03:12:45 +00:00
|
|
|
|
{ AddLine(Severity.Invalid, V317, CheckIdentifier.Form); return; }
|
2017-02-02 05:59:39 +00:00
|
|
|
|
}
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.AltForm > 0 && new[] {Legal.BattleForms, Legal.BattleMegas, Legal.BattlePrimals}.Any(arr => arr.Contains(pkm.Species)))
|
2017-03-23 03:12:45 +00:00
|
|
|
|
{ AddLine(Severity.Invalid, V310, CheckIdentifier.Form); return; }
|
2016-04-14 10:17:03 +00:00
|
|
|
|
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Valid, V318, CheckIdentifier.Form);
|
2016-04-14 10:17:03 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyMiscG1()
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
{
|
2017-06-21 16:18:33 +00:00
|
|
|
|
if (pkm.IsEgg)
|
|
|
|
|
{
|
|
|
|
|
VerifyMiscEggCommon();
|
|
|
|
|
if (pkm.PKRS_Cured || pkm.PKRS_Infected)
|
|
|
|
|
AddLine(Severity.Invalid, V368, CheckIdentifier.Egg);
|
|
|
|
|
}
|
2017-09-06 16:12:56 +00:00
|
|
|
|
|
2017-09-05 01:55:15 +00:00
|
|
|
|
if (!(pkm is PK1 pk1))
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2017-09-05 01:55:15 +00:00
|
|
|
|
VerifyMiscG1Types(pk1);
|
|
|
|
|
VerifyMiscG1CatchRate(pk1);
|
|
|
|
|
}
|
|
|
|
|
private void VerifyMiscG1Types(PK1 pk1)
|
|
|
|
|
{
|
|
|
|
|
var Type_A = pk1.Type_A;
|
|
|
|
|
var Type_B = pk1.Type_B;
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
if (pkm.Species == 137)
|
|
|
|
|
{
|
|
|
|
|
// Porygon can have any type combination of any generation 1 species because of the move Conversion,
|
|
|
|
|
// that change Porygon type to match the oponent types
|
|
|
|
|
var Type_A_Match = Legal.Types_Gen1.Any(t => t == Type_A);
|
|
|
|
|
var Type_B_Match = Legal.Types_Gen1.Any(t => t == Type_B);
|
|
|
|
|
if (!Type_A_Match)
|
|
|
|
|
AddLine(Severity.Invalid, V386, CheckIdentifier.Misc);
|
|
|
|
|
if (!Type_B_Match)
|
|
|
|
|
AddLine(Severity.Invalid, V387, CheckIdentifier.Misc);
|
|
|
|
|
if (Type_A_Match && Type_B_Match)
|
|
|
|
|
{
|
|
|
|
|
var TypesAB_Match = PersonalTable.RB.IsValidTypeCombination(Type_A, Type_B);
|
|
|
|
|
if (TypesAB_Match)
|
|
|
|
|
AddLine(Severity.Valid, V391, CheckIdentifier.Misc);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V388, CheckIdentifier.Misc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // Types must match species types
|
|
|
|
|
{
|
2018-03-25 20:53:48 +00:00
|
|
|
|
var Type_A_Match = Type_A == PersonalTable.RB[pkm.Species].Type1;
|
|
|
|
|
var Type_B_Match = Type_B == PersonalTable.RB[pkm.Species].Type2;
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
|
2017-09-05 01:55:15 +00:00
|
|
|
|
AddLine(Type_A_Match ? Severity.Valid : Severity.Invalid, Type_A_Match ? V392 : V389, CheckIdentifier.Misc);
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
AddLine(Type_B_Match ? Severity.Valid : Severity.Invalid, Type_B_Match ? V393 : V390, CheckIdentifier.Misc);
|
|
|
|
|
}
|
2017-09-05 01:55:15 +00:00
|
|
|
|
}
|
|
|
|
|
private void VerifyMiscG1CatchRate(PK1 pk1)
|
|
|
|
|
{
|
|
|
|
|
var catch_rate = pk1.Catch_Rate;
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
switch (pkm.TradebackStatus)
|
|
|
|
|
{
|
|
|
|
|
case TradebackType.Any:
|
|
|
|
|
case TradebackType.WasTradeback:
|
|
|
|
|
if (catch_rate == 0 || Legal.HeldItems_GSC.Any(h => h == catch_rate))
|
2017-09-05 01:55:15 +00:00
|
|
|
|
AddLine(Severity.Valid, V394, CheckIdentifier.Misc);
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
else if (pkm.TradebackStatus == TradebackType.WasTradeback)
|
2017-09-05 01:55:15 +00:00
|
|
|
|
AddLine(Severity.Invalid, V395, CheckIdentifier.Misc);
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
else
|
|
|
|
|
goto case TradebackType.Gen1_NotTradeback;
|
|
|
|
|
break;
|
|
|
|
|
case TradebackType.Gen1_NotTradeback:
|
2017-05-01 15:25:20 +00:00
|
|
|
|
if ((EncounterMatch as EncounterStatic)?.Version == GameVersion.Stadium || EncounterMatch is EncounterTradeCatchRate)
|
2017-09-05 01:55:15 +00:00
|
|
|
|
// Encounters detected by the catch rate, cant be invalid if match this encounters
|
|
|
|
|
AddLine(Severity.Valid, V398, CheckIdentifier.Misc);
|
|
|
|
|
if (pkm.Species == 149 && catch_rate == PersonalTable.Y[149].CatchRate || Legal.Species_NotAvailable_CatchRate.Contains(pkm.Species) && catch_rate == PersonalTable.RB[pkm.Species].CatchRate)
|
|
|
|
|
AddLine(Severity.Invalid, V396, CheckIdentifier.Misc);
|
2017-06-21 00:57:23 +00:00
|
|
|
|
else if (!Info.EvoChainsAllGens[1].Any(e => catch_rate == PersonalTable.RB[e.Species].CatchRate || catch_rate == PersonalTable.Y[e.Species].CatchRate))
|
2017-09-05 01:55:15 +00:00
|
|
|
|
AddLine(Severity.Invalid, pkm.Gen1_NotTradeback ? V397 : V399, CheckIdentifier.Misc);
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
else
|
2017-09-05 01:55:15 +00:00
|
|
|
|
AddLine(Severity.Valid, V398, CheckIdentifier.Misc);
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyMisc()
|
2016-04-22 02:32:22 +00:00
|
|
|
|
{
|
2017-01-26 19:16:21 +00:00
|
|
|
|
if (pkm.Format == 7 && ((PK7)pkm).PelagoEventStatus != 0)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Figure out what PelagoEventStati are legal.
|
|
|
|
|
}
|
2017-01-25 07:34:50 +00:00
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.IsEgg)
|
2016-09-03 15:10:22 +00:00
|
|
|
|
{
|
2017-06-21 16:18:33 +00:00
|
|
|
|
VerifyMiscEggCommon();
|
|
|
|
|
|
2016-10-23 19:48:49 +00:00
|
|
|
|
if (pkm.CNTs.Any(stat => stat > 0))
|
2017-06-15 04:07:42 +00:00
|
|
|
|
AddLine(Severity.Invalid, V320, CheckIdentifier.Egg);
|
2017-06-18 05:16:24 +00:00
|
|
|
|
if (pkm is PK4 pk4)
|
|
|
|
|
{
|
|
|
|
|
if (pk4.ShinyLeaf != 0)
|
|
|
|
|
AddLine(Severity.Invalid, V414, CheckIdentifier.Egg);
|
|
|
|
|
if (pk4.PokéathlonStat != 0)
|
|
|
|
|
AddLine(Severity.Invalid, V415, CheckIdentifier.Egg);
|
|
|
|
|
}
|
2018-01-07 06:43:48 +00:00
|
|
|
|
if (pkm is PK3)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.Language != 1) // All Eggs are Japanese and flagged specially for localized string
|
|
|
|
|
AddLine(Severity.Invalid, string.Format(V5, LanguageID.Japanese, (LanguageID)pkm.Language), CheckIdentifier.Egg);
|
|
|
|
|
}
|
2016-09-03 15:10:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-03 22:16:24 +00:00
|
|
|
|
if (!Encounter.Valid)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-09-06 03:32:07 +00:00
|
|
|
|
if (Info.Generation == 5)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyNsPKM();
|
2017-06-04 01:40:44 +00:00
|
|
|
|
|
2017-09-20 02:18:13 +00:00
|
|
|
|
VerifyMiscFatefulEncounter();
|
|
|
|
|
}
|
|
|
|
|
private void VerifyMiscFatefulEncounter()
|
|
|
|
|
{
|
2017-06-15 04:07:42 +00:00
|
|
|
|
switch (EncounterMatch)
|
|
|
|
|
{
|
2017-06-15 04:57:23 +00:00
|
|
|
|
case WC3 w when w.Fateful:
|
2017-09-20 02:18:13 +00:00
|
|
|
|
if (w.IsEgg)
|
|
|
|
|
{
|
|
|
|
|
// Eggs hatched in RS clear the obedience flag!
|
|
|
|
|
if (pkm.Format != 3)
|
|
|
|
|
return; // possible hatched in either game, don't bother checking
|
|
|
|
|
if (pkm.Met_Location <= 087) // hatched in RS
|
|
|
|
|
break; // ensure fateful is not active
|
|
|
|
|
// else, ensure fateful is active (via below)
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyFatefulIngameActive();
|
2017-10-19 01:18:23 +00:00
|
|
|
|
VerifyWC3Shiny(w);
|
2017-06-15 04:57:23 +00:00
|
|
|
|
return;
|
2017-10-19 01:18:23 +00:00
|
|
|
|
case WC3 w:
|
|
|
|
|
VerifyWC3Shiny(w);
|
|
|
|
|
break;
|
2017-06-17 04:45:03 +00:00
|
|
|
|
case MysteryGift g when g.Format != 3: // WC3
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyFatefulMysteryGift(g);
|
2017-06-15 04:07:42 +00:00
|
|
|
|
return;
|
|
|
|
|
case EncounterStatic s when s.Fateful: // ingame fateful
|
|
|
|
|
case EncounterSlot _ when pkm.Version == 15: // ingame pokespot
|
2017-09-21 04:28:29 +00:00
|
|
|
|
case EncounterTrade t when t.Fateful:
|
2017-06-18 01:37:19 +00:00
|
|
|
|
VerifyFatefulIngameActive();
|
2017-06-15 04:07:42 +00:00
|
|
|
|
return;
|
2017-06-03 22:16:24 +00:00
|
|
|
|
}
|
2017-09-20 02:18:13 +00:00
|
|
|
|
if (pkm.FatefulEncounter)
|
|
|
|
|
AddLine(Severity.Invalid, V325, CheckIdentifier.Fateful);
|
2017-06-15 04:07:42 +00:00
|
|
|
|
}
|
2017-06-21 16:18:33 +00:00
|
|
|
|
private void VerifyMiscEggCommon()
|
|
|
|
|
{
|
|
|
|
|
if (new[] {pkm.Move1_PPUps, pkm.Move2_PPUps, pkm.Move3_PPUps, pkm.Move4_PPUps}.Any(ppup => ppup > 0))
|
|
|
|
|
AddLine(Severity.Invalid, V319, CheckIdentifier.Egg);
|
|
|
|
|
if (pkm.Move1_PP != pkm.GetMovePP(pkm.Move1, 0) || pkm.Move2_PP != pkm.GetMovePP(pkm.Move2, 0)
|
|
|
|
|
|| pkm.Move3_PP != pkm.GetMovePP(pkm.Move3, 0) || pkm.Move4_PP != pkm.GetMovePP(pkm.Move4, 0))
|
|
|
|
|
AddLine(Severity.Invalid, V420, CheckIdentifier.Egg);
|
|
|
|
|
|
|
|
|
|
var HatchCycles = (EncounterMatch as EncounterStatic)?.EggCycles;
|
|
|
|
|
if (HatchCycles == 0 || HatchCycles == null)
|
|
|
|
|
HatchCycles = pkm.PersonalInfo.HatchCycles;
|
|
|
|
|
if (pkm.CurrentFriendship > HatchCycles)
|
|
|
|
|
AddLine(Severity.Invalid, V374, CheckIdentifier.Egg);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyFatefulMysteryGift(MysteryGift g)
|
2017-06-15 04:07:42 +00:00
|
|
|
|
{
|
|
|
|
|
if (g is PGF p && p.IsShiny)
|
2017-06-03 22:16:24 +00:00
|
|
|
|
{
|
2017-06-21 00:57:23 +00:00
|
|
|
|
Info.PIDIV = MethodFinder.Analyze(pkm);
|
2018-01-29 07:40:57 +00:00
|
|
|
|
if (Info.PIDIV.Type != PIDType.G5MGShiny && pkm.Egg_Location != 30003)
|
2017-06-15 04:07:42 +00:00
|
|
|
|
AddLine(Severity.Invalid, V411, CheckIdentifier.PID);
|
|
|
|
|
}
|
2017-06-03 22:16:24 +00:00
|
|
|
|
|
2017-10-19 01:18:23 +00:00
|
|
|
|
if (pkm.FatefulEncounter)
|
2017-06-15 04:07:42 +00:00
|
|
|
|
AddLine(Severity.Valid, V321, CheckIdentifier.Fateful);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V322, CheckIdentifier.Fateful);
|
|
|
|
|
}
|
2017-10-19 01:18:23 +00:00
|
|
|
|
private void VerifyWC3Shiny(WC3 g3)
|
|
|
|
|
{
|
|
|
|
|
// check for shiny locked gifts
|
2018-03-17 02:35:55 +00:00
|
|
|
|
if (!g3.Shiny.IsValid(pkm))
|
2017-10-19 01:18:23 +00:00
|
|
|
|
AddLine(Severity.Invalid, V409, CheckIdentifier.Fateful);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyFatefulIngameActive()
|
2017-06-15 04:07:42 +00:00
|
|
|
|
{
|
2017-08-21 15:59:26 +00:00
|
|
|
|
if (pkm.Version == 15 && pkm is XK3 xk3 && Info.WasXD)
|
|
|
|
|
{
|
|
|
|
|
// can't have fateful until traded away, which clears ShadowID
|
|
|
|
|
if (xk3.FatefulEncounter && xk3.ShadowID != 0)
|
|
|
|
|
AddLine(Severity.Invalid, V325, CheckIdentifier.Fateful);
|
|
|
|
|
|
2017-07-04 20:24:12 +00:00
|
|
|
|
return; // fateful is set when transferred away
|
2017-08-21 15:59:26 +00:00
|
|
|
|
}
|
2017-07-04 20:24:12 +00:00
|
|
|
|
|
2017-06-15 04:07:42 +00:00
|
|
|
|
if (pkm.FatefulEncounter)
|
|
|
|
|
AddLine(Severity.Valid, V323, CheckIdentifier.Fateful);
|
|
|
|
|
else
|
|
|
|
|
AddLine(Severity.Invalid, V324, CheckIdentifier.Fateful);
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyNsPKM()
|
2017-06-15 04:07:42 +00:00
|
|
|
|
{
|
2017-12-18 23:25:40 +00:00
|
|
|
|
bool req = EncounterMatch is EncounterStaticPID s && s.NSparkle;
|
2017-06-15 04:07:42 +00:00
|
|
|
|
if (pkm.Format == 5)
|
|
|
|
|
{
|
|
|
|
|
bool has = ((PK5)pkm).NPokémon;
|
|
|
|
|
if (req && !has)
|
|
|
|
|
AddLine(Severity.Invalid, V326, CheckIdentifier.Fateful);
|
|
|
|
|
if (!req && has)
|
|
|
|
|
AddLine(Severity.Invalid, V327, CheckIdentifier.Fateful);
|
|
|
|
|
}
|
|
|
|
|
if (req)
|
|
|
|
|
{
|
|
|
|
|
if (pkm.IVs.Any(iv => iv != 30))
|
|
|
|
|
AddLine(Severity.Invalid, V218, CheckIdentifier.IVs);
|
2017-08-12 08:30:19 +00:00
|
|
|
|
if (!VerifyNsPKMOTValid())
|
2017-06-15 04:07:42 +00:00
|
|
|
|
AddLine(Severity.Invalid, V219, CheckIdentifier.Trainer);
|
|
|
|
|
if (pkm.IsShiny)
|
|
|
|
|
AddLine(Severity.Invalid, V220, CheckIdentifier.Shiny);
|
2016-04-22 02:32:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-12 08:30:19 +00:00
|
|
|
|
private bool VerifyNsPKMOTValid()
|
|
|
|
|
{
|
|
|
|
|
if (pkm.TID != 00002 || pkm.SID != 00000)
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-10-23 04:01:08 +00:00
|
|
|
|
var OT = pkm.Language == (int)LanguageID.Japanese ? "N" : "N";
|
2017-09-20 04:35:30 +00:00
|
|
|
|
return OT == pkm.OT_Name;
|
2017-08-12 08:30:19 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private void VerifyVersionEvolution()
|
2016-12-01 03:37:53 +00:00
|
|
|
|
{
|
|
|
|
|
if (pkm.Format < 7)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// No point using the evolution tree. Just handle certain species.
|
2017-09-20 04:35:30 +00:00
|
|
|
|
bool Sun() => pkm.Version == (int)GameVersion.SN || pkm.Version == (int)GameVersion.US;
|
|
|
|
|
bool Moon() => pkm.Version == (int)GameVersion.MN || pkm.Version == (int)GameVersion.UM;
|
2016-12-01 03:37:53 +00:00
|
|
|
|
switch (pkm.Species)
|
|
|
|
|
{
|
|
|
|
|
case 745: // Lycanroc
|
|
|
|
|
if (!pkm.WasEgg)
|
|
|
|
|
break;
|
|
|
|
|
|
2017-09-20 04:35:30 +00:00
|
|
|
|
if (pkm.AltForm == 0 && Moon()
|
|
|
|
|
|| pkm.AltForm == 1 && Sun())
|
2016-12-01 03:37:53 +00:00
|
|
|
|
if (pkm.IsUntraded)
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V328, CheckIdentifier.Evolution);
|
2016-12-01 03:37:53 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 791: // Solgaleo
|
2017-09-20 04:35:30 +00:00
|
|
|
|
if (Moon() && pkm.IsUntraded)
|
2016-12-01 03:37:53 +00:00
|
|
|
|
{
|
2017-05-28 05:40:21 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift g && g.Species == pkm.Species) // Gifted via Mystery Gift
|
2016-12-01 03:37:53 +00:00
|
|
|
|
break;
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V328, CheckIdentifier.Evolution);
|
2016-12-01 03:37:53 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 792: // Lunala
|
2017-09-20 04:35:30 +00:00
|
|
|
|
if (Sun() && pkm.IsUntraded)
|
2016-12-01 03:37:53 +00:00
|
|
|
|
{
|
2017-05-28 05:40:21 +00:00
|
|
|
|
if (EncounterMatch is MysteryGift g && g.Species == pkm.Species) // Gifted via Mystery Gift
|
2016-12-01 03:37:53 +00:00
|
|
|
|
break;
|
2017-03-23 03:12:45 +00:00
|
|
|
|
AddLine(Severity.Invalid, V328, CheckIdentifier.Evolution);
|
2016-12-01 03:37:53 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-04 02:51:29 +00:00
|
|
|
|
public static string[] MoveStrings { internal get; set; } = Util.GetMovesList("en");
|
|
|
|
|
public static string[] SpeciesStrings { internal get; set; } = Util.GetSpeciesList("en");
|
|
|
|
|
internal static IEnumerable<string> getMoveNames(IEnumerable<int> moves) => moves.Select(m => m >= MoveStrings.Length ? V190 : MoveStrings[m]);
|
2016-03-11 04:36:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|